LocalNow vs FixedLocalNow или который час?

#АнатомияФункций - DateTime.LocalNow, DateTime.FixedLocalNow, DateTimeZone.UtcNow, DateTimeZone.FixedUtcNow , DateTimeZone.LocalNow, DateTimeZone.FixedLocalNow



Всем привет!



В каментах просили разобрать разницу между функциями получения текущих даты и времени. Базово функций три:

DateTime.LocalNow – возвращает системные дату и время;

DateTimeZone.LocalNow – возвращает системные дату, время и часовой пояс

DateTimeZone.UtcNow – возвращает всемирное координированное время



При этом у каждой есть её фиксированный вариант - DateTime.FixedLocalNow, DateTimeZone.FixedLocalNow, DateTimeZone.FixedUtcNow.

Идея фиксации состоит в том, что в ходе запроса функция вычисляется ровно один раз и уже не меняет своё значение при множественных вызовах.



Давайте сравним:

let

tr = List.Count(List.Distinct(List.Transform({1..100000},(x)=>DateTime.LocalNow()))),//<>1

tbl = Table.RowCount(Table.Distinct(Table.FromList({1..100000},(x)=>{DateTime.LocalNow()}))),//<>1

acc =List.Count(List.Distinct(List.Accumulate({1..1000},{},(x,y)=>x&{DateTime.LocalNow()})))//<>1

in

acc


На каждом шаге запроса вы сможете увидеть значение, отличающееся от единицы – происходит множественный вызов функции, соответственно значения отличаются (вообще они отличаются в долях секунды, поэтому если вас интересует только текущая дата – это ни разу не принципиально)



Но при этом фиксированные варианты дадут:

let

tr = List.Count(List.Distinct(List.Transform({1..100000},(x)=>DateTime.FixedLocalNow()))),//1

tbl = Table.RowCount(Table.Distinct(Table.FromList({1..100000},(x)=>{DateTime.FixedLocalNow()}))),//1

acc =List.Count(List.Distinct(List.Accumulate({1..1000},{},(x,y)=>x&{DateTime.FixedLocalNow()})))//1

in

acc


Т.е. видим, что действительно на каждом шаге ровно одно уникальное датавремя.



Если кому-то принципиальны доли секунды и он уже побежал переписывать все свои запросы – остановитесь! И посмотрите следующий код:

let

now = DateTime.LocalNow(),

tr = List.Count(List.Distinct(List.Transform({1..100000},(x)=>now))),//1

tbl = Table.RowCount(Table.Distinct(Table.FromList({1..100000},(x)=>{now}))),//1

acc =List.Count(List.Distinct(List.Accumulate({1..1000},{},(x,y)=>x&{now})))//1

in

acc


Т.е. если вы, как и я, являетесь противниками множественных вызовов и используете переменные (в данном случае now), то проблемы у вас нет – функция вызывается один раз при вычислении переменной. Заодно это немного (процентов на 5%) ускоряет вычисления – мелочь, а приятно.



Ну и раз уж нас интересует прям точное время, то нельзя не вспомнить, что, например, в командировке у вас может измениться часовой пояс и могут «поехать» вычисления. В этой ситуации целесообразно это учитывать и в переменную засовывать функции, учитывающие часовой пояс, результат выполнения которых можно пересчитать на интересующий. В примере ниже в переменных оказывается Питерское время, даже если я в Шанхае:

let

now = DateTime.From(DateTimeZone.SwitchZone(DateTimeZone.UtcNow(),3)),

now1 = DateTime.From(DateTimeZone.SwitchZone(DateTimeZone.LocalNow(),3)),

now2 = DateTime.From(DateTimeZone.SwitchZone(DateTimeZone.FixedUtcNow(),3)),

now3 = DateTime.From(DateTimeZone.SwitchZone(DateTimeZone.FixedLocalNow(),3))

in

now3




Как-то так. Нет «правильных» или «неправильных» функций, есть вполне конкретное их поведение, которое нужно учитывать при написании кода )))



Ну а разбор всего этого безобразия смотрите, как всегда, на Ютубе



Лайк, коммент, подписка приветствуются )))



Надеюсь, было полезно.

Всех благ!

@buchlotnik