Проблема
Итак, на этот вопрос нет однозначного ответа. Проблема является фундаментальной для javascript, где вы можете видеть даты одним из двух способов:
- UT C (
getUTCHours()
, getUTCMinutes()
et c.) - локальный (то есть системный,
getHours()
, getMinutes()
и c.)
И нет указанного способа установить эффективный системный часовой пояс, или даже смещение UT C, если на то пошло.
(Просмотрите mdn Date
ссылку или проверку spe c, чтобы получить ощущение того, насколько все это бесполезно.)
«Но подождите!» мы плачем: «Разве не поэтому существует moment-timezone
??»
Не совсем так. moment
и moment-timezone
дают гораздо лучший / более легкий контроль над управлением временем в javascript, но даже у них нет возможности узнать, какой местный часовой пояс использует Date
, и использовать другие механизмы, чтобы узнать это. Проблема заключается в следующем.
После того, как вы ознакомитесь с кодом, вы увидите, что метод момента .local()
( объявление прототипа и реализация setOffsetToLocal ) of moment эффективно выполняет следующее:
- устанавливает UT C смещение момента на 0
- отключает «UT C mode», устанавливая
_isUTC
в false.
Эффект отключения «режима UT C» означает, что большинство методов доступа перенаправляются базовому объекту Date
. Например, .hours()
в конечном итоге вызывает moment / get-set. js get()
который выглядит так:
export function get(mom, unit) {
return mom.isValid()
? mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]()
: NaN;
}
_d
- это Date
объект, оборачиваемый моментом (mom
). Так что эффективно для момента не-UT C режима, moment.hours()
- это переход на Date.prototype.getHours()
. Не имеет значения, что вы установили с помощью moment.tz.setDefault()
, или переопределили ли вы Date.now()
. Ни одна из этих вещей не используется.
Другое дело ...
Вы сказали:
По сути, я хочу жестко закодировать свое время, чтобы быть Америкой / Нью-Йорком и хотите, чтобы эта функция работала согласованно
Но на самом деле это обычно невозможно. Вы используете Chica go, который, как мне кажется, имеет сдвиги синхронно c с Нью-Йорком, но, например, Великобритания смещается в другое время по сравнению с США, поэтому в году будут недели, когда ваш тест будет потерпеть неудачу, если вы конвертировали часовой пояс США в часовой пояс Великобритании.
Решения.
Но это все равно разочаровывает, потому что мне не нужны мои разработчики в Польше и Америка должна провести локальные тесты, потому что мой CI-сервер работает в UT C. Итак, что мы можем с этим поделать?
Первое решение - это не решение: найдите другой способ делать то, что вы делаете! Как правило, варианты использования .local()
весьма ограничены и должны отображать пользователю время в его текущем смещении . Это даже не их часовой пояс, потому что локальные методы Date
будут смотреть только на текущее смещение. Таким образом, в большинстве случаев вы хотите использовать его только для текущего времени или, если вы не возражаете, если это неверно для половины объектов Date
, для которых вы его используете (для часовых поясов, использующих летнее время). Было бы лучше узнать часовой пояс, который хочет пользователь, другими способами, а не использовать .local()
вообще.
Второе решение тоже не является решением: не беспокойтесь о ваших тестах так много! Главное с отображением местного времени - это то, что оно работает, вам все равно, что именно. Убедитесь вручную, что он отображает правильное время, и в ваших тестах просто убедитесь, что он возвращает разумно выглядящую вещь, без проверки указанного c времени.
Если вы все еще хотите продолжить, по крайней мере, это последнее решение делает ваше дело и некоторые другие работоспособными, и очевидно, что вам нужно делать, если вы обнаружите, что вам нужно его расширить. Однако это сложная область, и я не даю никаких гарантий, что это не приведет к нежелательным побочным эффектам!
В вашем файле настройки теста:
[
'Date',
'Day',
'FullYear',
'Hours',
'Minutes',
'Month',
'Seconds',
].forEach(
(prop) => {
Date.prototype[`get${prop}`] = function () {
return new Date(
this.getTime()
+ moment(this.getTime()).utcOffset() * 60000
)[`getUTC${prop}`]();
};
}
);
Теперь вы должны иметь возможность использовать moment.tz.setDefault()
, а использование .local()
должно позволить вам получить доступ к свойствам datetime, как если бы он думал, что местный часовой пояс настроен в moment-timezone
.
Я думал попробовать исправить moment
вместо этого, но это гораздо более сложный зверь, чем Date
, и исправление Date
должно быть надежным, поскольку это примитив.