Получите количество миллисекунд для локализованной даты с учетом летнего времени - PullRequest
1 голос
/ 15 апреля 2019

У меня есть данные в Google BigQuery, которые выглядят так:


sample_date_time_UTC     time_zone       milliseconds_between_samples
--------                 ---------       ----------------------------
2019-03-31 01:06:03 UTC  Europe/Paris    60000
2019-03-31 01:16:03 UTC  Europe/Paris    60000
...

Выборки данных ожидаются через равные промежутки времени, о чем свидетельствует значение поля milliseconds_between_samples:

time_zone - это строка, представляющая облако Google Поддерживаемое значение часового пояса


Затем я проверяю соотношение фактического количества выборок к ожидаемому числу зав любой конкретный день для любого отдельного дневного диапазона (выраженного в виде локальной даты для данного time_zone):

with data as 
  ( 
    select 
      -- convert sample_date_time_UTC to equivalent local datetime for the timezone
      DATETIME(sample_date_time_UTC,time_zone) as localised_sample_date_time, 
      milliseconds_between_samples 
    from  `mytable` 
    where sample_date_time between '2019-03-31 00:00:00.000000+01:00' and '2019-04-01 00:00:00.000000+02:00'
  ) 

select date(localised_sample_date_time) as localised_date, count(*)/(86400000/avg(milliseconds_between_samples)) as ratio_of_daily_sample_count_to_expected 
from data 
group by localised_date 
order by localised_date 

Проблема заключается в том, что в этом есть ошибка, поскольку я жестко закодировал ожидаемое числомиллисекунд в день до 86400000.Это неверно, так как, когда летнее время начинается с указанного time_zone (Europe/Paris), день становится на 1 час короче.Когда летнее время заканчивается, день увеличивается на 1 час.

Таким образом, приведенный выше запрос неверен.Он запрашивает данные за 31 марта этого года в часовом поясе Europe/Paris (когда в этом часовом поясе началось летнее время).Миллисекунды в этот день должны быть 82800000.

. В запросе как получить правильное количество миллисекунд для указанного localised_date?

Обновление:

Я попытался сделать это, чтобы увидеть, что он возвращает:

select DATETIME_DIFF(DATETIME('2019-04-01 00:00:00.000000+02:00', 'Europe/Paris'), DATETIME('2019-03-31 00:00:00.000000+01:00', 'Europe/Paris'), MILLISECOND)

Это не сработало - я получаю 86400000

Ответы [ 2 ]

1 голос
/ 16 апреля 2019

Спасибо @Juta, за подсказку по использованию времени UTC для расчета. Поскольку я группирую свои данные для каждого дня по локализованной дате, я понял, что могу вычислять миллисекунды для каждого дня, получая дату начала и окончания (в UTC) для моей «локализованной» даты, используя следующую логику :

-- get UTC start datetime for localised date
-- get UTC end datetime for localised date

-- this then gives the milliseconds for that localised date:
datetime_diff(utc_end_datetime, utc_start_datetime, MILLISECOND);

Итак, мой полный запрос:

with daily_sample_count as (
  with data as 
    ( 
      select 
        -- get the date in the local timezone, for sample_date_time_UTC
        DATE(sample_date_time_UTC,time_zone) as localised_date, 
        milliseconds_between_samples 
      from  `mytable` 
      where sample_date_time between '2019-03-31 00:00:00.000000+01:00' and '2019-04-01 00:00:00.000000+02:00'
    ) 

  select
    localised_date,
    count(*) as daily_record_count,
    avg(milliseconds_between_samples) as daily_avg_millis_between_samples,
    datetime(timestamp(localised_date, time_zone)) as utc_start_datetime,
    datetime(timestamp(date_add(localised_date, interval 1 day), time_zone)) as utc_end_datetime
  from data 
)

select
  localised_date,
  -- apply calculation for ratio_of_daily_sample_count_to_expected
  -- based on the actual vs expected number of samples for the day
  -- no. of milliseconds in the day changes, when transitioning in/out of daylight saving - so we calculate milliseconds in the day
  daily_record_count/(datetime_diff(utc_end_datetime, utc_start_datetime, MILLISECOND)/daily_avg_millis_between_samples) as ratio_of_daily_sample_count_to_expected
from
  daily_sample_count
1 голос
/ 15 апреля 2019

Вы можете получить разницу в миллисекундах для двух временных отметок, удалив +01:00 и +02:00. Обратите внимание, что это дает разницу между временными метками в UTC: 90000000, которая не совпадает с фактическими прошедшими миллисекундами.

Вы можете сделать что-то вроде этого, чтобы получить миллисекунды за один день:

select 86400000 + (86400000 - DATETIME_DIFF(DATETIME('2019-04-01 00:00:00.000000', 'Europe/Paris'), DATETIME('2019-03-31 00:00:00.000000', 'Europe/Paris'), MILLISECOND))
...