Rrule: UTC-しかしUTCではない混乱

䜜成日 2019幎04月05日  Â·  18コメント  Â·  ゜ヌス: jakubroztocil/rrule

これはrruleの問題ではないず思いたすが、rruleやタむムゟヌンのサポヌトに぀いおの私の理解がありたす。 rruleずluxonのドキュメントの関連セクションをすでに読みたした。

コヌドサンプル

const { RRule, RRuleSet } = require(`rrule`);

const dtstart = new Date();
console.log(`dtstart`, dtstart);

const firstHour = dtstart.getHours();
const secondHour = (firstHour + 2) % 24;

const getRRule = options => new RRule(Object.assign({}, options, {
    freq: RRule.DAILY,
    count: 1,
    dtstart,
    byminute: 0,
    bysecond: 0
}));

const showNextInstance = tzid => {
    const ruleSet = new RRuleSet();
    ruleSet.rrule(getRRule({ tzid, byhour: firstHour }));
    ruleSet.rrule(getRRule({ tzid, byhour: secondHour }));
    console.log(tzid, ruleSet.after(dtstart));
};

showNextInstance(undefined);
showNextInstance(`UTC`);
showNextInstance(`local`);
showNextInstance(`America/Chicago`);

実際の出力

dtstart 2019-04-05T11:51:23.744Z
undefined 2019-04-06T06:00:00.744Z
UTC 2019-04-06T06:00:00.744Z
local 2019-04-06T06:00:00.744Z
America/Chicago 2019-04-06T06:00:00.744Z

期埅される出力

tzidは出力に䜕らかの圱響を䞎えるず思いたすが、各タむムゟヌンで同じ出力が生成されたす。

たた、ルヌルで指定された時間ず次のむベントむンスタンスの出力ずの盞関関係もわかりたせん。 次のむンスタンスは、指定されたdtstartずtzid倀がどのように解釈たたは適甚されるかに応じお、提䟛されたルヌルによっお衚される2時間のうちの1぀にほが察応するず予想したす。

rruleバヌゞョン

2.6.0

オペレヌティング・システム

OS X 10.14.2、ノヌド8.11.4

ロヌカルタむムゟヌン

$ date
Fri Apr  5 06:32:33 CDT 2019

最も参考になるコメント

私はそれがでconflateの問題には簡単だず思うDateオブゞェクトず問題の発生を蚈算するRRULE私は2぀を組み合わせる前に、個別にそれらに぀いおの話をする぀もりですので、。 私はこれをほずんど曞き留めなければならなかったので、問題の理解を敎理し、他の人に圹立぀堎合に備えおここに投皿するこずにしたした。

JavaScriptの日付オブゞェクト

JS Dateオブゞェクトが䞍芏則であるこずに同意したせんが、オブゞェクトにはよくある誀解があり、そのように芋えたす。 控えめに蚀っおも混乱したす。

@ hlee5zebraで述べたように、 Dateコンストラクタヌで䜜成された日付は垞にUTCで衚されたす。 それらは珟地時間で衚瀺される堎合がありたすが、舞台裏では実際にはUnix゚ポック時間で衚されたす。 むンスタンス化されたDateオブゞェクトに察しおい぀でも.getTime()たたは.toISOString()しお、UTCで䜜業しおいるこずを思い出させるこずができたす。

実装は、UTCですべおの凊理を実行し、ナヌザヌに衚瀺される珟地時間にのみ倉換するずいう芏則にも正しく準拠しおいたす。 たたたた、開発者である私たちがナヌザヌです。 しかしそれから私達は氎を濁らせる私達自身のナヌザヌを念頭に眮いおいたす。 アプリを開発するずきは、芏則に埓い、バック゚ンドで日付をUTCずしお保存する必芁がありたすJSはすでにUTCで日付を凊理しおいるので、そこで問題ありたせん。 日付をUTCずしおデヌタストアに保存する堎合、日付はISO文字列ずしおクラむアントに到着し、 Dateオブゞェクトによっお正しく解析され、ナヌザヌの珟地時間に衚瀺される必芁がありたす。

この蚘事は、 Dateオブゞェクトを理解し、それを䜿っおどれだけできるかを発芋するのに圹立ちたした https 

ルヌル

RRULEオカレンスの蚈算は、ナヌザヌの期埅ずUTCでの日付の凊理に根本的な違いがあるため、泚意が必芁です。これら2぀の時間衚珟が1日の障壁を超えるず顕著になりたす。

たずえば、ナヌザヌが毎週火曜日に発生する再発を垌望する堎合、ナヌザヌはすべおの発生が珟地時間の火曜日に発生するこずを期埅したす。 ただし、すべおの蚈算はUTCで行われるため、 RRULEようになりたす。

DTSTART:2019-10-29T00:02:26Z
RRULE:FREQ=WEEKLY;BYWEEKDAY=TU

UTCの火曜日にオカレンスを返したすが、本初子午線のかなり西に䜍眮するナヌザヌの堎合、オカレンスは珟地時間の月曜日に衚瀺されたす。これは明らかに、誰もが望んでいる結果ではありたせん。

それを正しくする

ずはいえ、これを解決するために開発者がしなければならないこずは、JavaScriptにロヌカル日付が実際にはUTC日付であるず考えさせ、その「停の」日付をrrule.jsに䞎え、ラむブラリに蚈算を行わせるこずです。このロヌカルUTC時間。 .all()メ゜ッドからオカレンスを取埗したら、それらの日付の「UTC」郚分を䜿甚しお、新しいDateオブゞェクトをむンスタンス化したす。 これにより、結果が期埅どおりになりたす。

import { RRule } from 'rrule'

const dtstart = new Date('2019-10-29T00:02:26Z') // same as: `new Date(Date.UTC(2019, 9, 29, 0, 2, 26))`
console.log(dtstart.toISOString()) // 2019-10-29T00:02:26.000Z
console.log(dtstart) // Mon Oct 28 2019 17:02:26 GMT-0700 (Pacific Daylight Time)

const fakeDateStart = setPartsToUTCDate(dtstart)
console.log(fakeDateStart.toISOString()) // 2019-10-28T17:02:26.000Z
console.log(fakeDateStart) // Mon Oct 28 2019 10:02:26 GMT-0700 (Pacific Daylight Time)

const rule = new RRule({
  freq: RRule.WEEKLY,
  byweekday: [RRule.TU],
  count: 2,
  dtstart: fakeDateStart
})

const localUTCOccurrences = rule.all()
console.log(localUTCOccurrences.map(toISOString)) // ["2019-10-29T17:02:26.000Z", "2019-11-05T17:02:26.000Z"]
console.log(localUTCOccurrences) // [Tue Oct 29 2019 10:02:26 GMT-0700 (Pacific Daylight Time), Tue Nov 05 2019 09:02:26 GMT-0800 (Pacific Standard Time)]

const occurrences = localUTCOccurrences.map(setUTCPartsToDate)
console.log(occurrences.map(toISOString)) // ["2019-10-30T00:02:26.000Z", "2019-11-06T01:02:26.000Z"]
console.log(occurrences) // [Tue Oct 29 2019 17:02:26 GMT-0700 (Pacific Daylight Time), Tue Nov 05 2019 17:02:26 GMT-0800 (Pacific Standard Time)]

function setPartsToUTCDate(d) {
  return new Date(
    Date.UTC(
      d.getFullYear(),
      d.getMonth(),
      d.getDate(),
      d.getHours(),
      d.getMinutes(),
      d.getSeconds()
    )
  )
}

function setUTCPartsToDate(d) {
  return new Date(
    d.getUTCFullYear(),
    d.getUTCMonth(),
    d.getUTCDate(),
    d.getUTCHours(),
    d.getUTCMinutes(),
    d.getUTCSeconds()
  )
}

function toISOString(d) {
  return d.toISOString()
}

https://codesandbox.io/s/rrule-localutc-conversion-zxlki

たたは芁するに

import { RRule } from 'rrule'

const date = new Date('2019-10-29T00:02:26Z')

const rule = new RRule({
  freq: RRule.WEEKLY,
  byweekday: [RRule.TU],
  count: 2,
  dtstart: setPartsToUTCDate(date)
})

const occurrences = rule.all().map(setUTCPartsToDate)

https://codesandbox.io/s/rrule-localutc-conversion-in-short-ez7g0

私が芋る限り、Chrome、Firefox、Safariはすべお、コン゜ヌルにログむンするずきに珟地時間の文字列ずしお日付を衚瀺し、UTCのISO文字列ずしおNode.jsを衚瀺したす。

党おのコメント18件

私もひどく混乱しおいたす。

わかりたした。Readmeに次の重芁な段萜がありたした。

image

ロヌカルタむムゟヌンには、これら2぀のヘルパヌ機胜を䜿甚する必芁がありたす。 tzidをサポヌトするようにこれを倉曎する堎合は、オフセットを倉曎しおXタむムゟヌンのオフセットを取埗する必芁がありたす。

/**
 * Mutates date. Add timezone to the date.
 *
 * <strong i="9">@param</strong> {Date} [date]
 */
export function localizeDate(date = new Date()) {
  const offset = new Date().getTimezoneOffset() * 60 * 1000; // get offset for local timezone (can modify here to support tzid)
  date.setTime(date.getTime() - offset);
  return date;
}

/**
 * Mutates a date. De-timezones a date.
 *
 * <strong i="10">@param</strong> {Date} [date]
 */
export function utcifyDate(date = new Date()) {
  const offset = new Date().getTimezoneOffset() * 60 * 1000; // get offset for local timezone (can modify here to support tzid)
  date.setTime(date.getTime() + offset);
  return date;
}

次に、コヌドは次のように倉曎されたす。

const { RRule, RRuleSet } = require(`rrule`);

const dtstart = localizeDate(new Date());
console.log(`dtstart`, utcifyDate(new Date(dtstart))); // even though it is utc string, this is the local time

const firstHour = dtstart.getUTCHours();
const secondHour = (firstHour + 2) % 24;

const getRRule = options => new RRule(Object.assign({}, options, {
    freq: RRule.DAILY,
    count: 1,
    dtstart,
    byminute: 0,
    bysecond: 0
}));

const showNextInstance = tzid => {
    const ruleSet = new RRuleSet();
    ruleSet.rrule(getRRule({ byhour: firstHour })); // remove tzid as i dont support this
    ruleSet.rrule(getRRule({ byhour: secondHour })); // removed tzid as i dont support this
    console.log('local:', utcifyDate(ruleSet.after(dtstart));
};

showNextInstance(undefined);
showNextInstance(`UTC`);
showNextInstance(`local`);
showNextInstance(`America/Chicago`);

JSの玛らわしく䞍芏則なDate実装に基づいお構築されおいるため、このラむブラリではこれを回避する良い方法はないのではないかず思いたす。 私は珟圚完党な曞き盎しに取り組んでいたすが、それを正しくするのに少し時間がかかりたす。

ありがずう@davidgoliあなたの仕事はずおも感謝しおいたす!!!

他の人が䞍芏則な日付の実装を理解するのを助けるために蚘事を曞くこずを理解しおいる誰かが必芁だず思いたす。 正盎なずころ、ただわかりたせん。うたくいくたで調敎したした。

これは、コン゜ヌルに出力する返される日付が文字列に倉換されるJavaScriptの日付であり、JavaScriptがUTCでコン゜ヌルに日付を自動的に出力するためですタむムスタンプの末尟にある「Z」を参照しおください。れロオフセット。 4぀のケヌスのそれぞれでの次の発生は異なるタむムゟヌンではありたすがたったく同時に発生しおいるため、たったく同じタむムスタンプが4回出力されたす。

たた、JavaScript Dateオブゞェクトは、1970幎1月1日朚曜日の00:00:00 UTCから経過したミリ秒数を䜿甚しお時間を远跡するこずに泚意しおください「UTC」に泚意しおください。 「12:34:56 pm」などの文字列の解釈。

@davidgoli

私は珟圚完党な曞き盎しに取り組んでいたすが、それを正しくするのに少し時間がかかりたす。

rScheduleの゜ヌスを確認するこずをお芋える浮動UTC日付に倉換する特別なDateTimeオブゞェクトLuxonからではないを䜿甚しお行われたす。 反埩はこのUTC日時で行われるため、DSTは問題になりたせん。 オカレンスが芋぀かった埌、ナヌザヌに枡される前に、適切なタむムゟヌンで通垞の日付に倉換されたす。

䟋この日付

import { DateTime as LuxonDateTime } from 'luxon';

const date = LuxonDateTime.fromObject({
  year: 2019,
  month: 1,
  day: 1,
  zone: 'America/Los_Angeles'
})

このUTC日付に倉換され、タむムゟヌンが保存されたす

const fakeDate = Date.UTC(2019, 0, 1)
const fakeDateZone = 'America/Los_Angeles'

このUTC日付はLuxon日付に䌌おいたすがどちらも2019/1/1ように芋えたす、異なるタむムゟヌンにあるため、実際には同じ時刻を衚しおいないこずに泚意しおください。

そうは蚀っおも、この特別な「UTC」日付で繰り返すこずで、倏時間を気にせずに繰り返すこずができたす。 正しい日付が芋぀かったら、ルク゜ンの日付に戻すこずができたす。

䟋えば

LuxonDateTime.fromObject({
  year: fakeDate.year,
  month: fakeDate.month,
  day: fakeDate.day,
  zone: fakeDateZone,
})

これにより、任意のタむムゟヌンをサポヌトしながら、反埩ロゞックをUTC察応に保぀こずができたす。

@thefliikプリミティブをダりンさせたした。 ここでの本圓の頭痛の皮は数週間です。 rscheduleもこれたでのずころbyweeknoずbysetposのサポヌトでパントしおいるようですが...

ああ、そうだ。 byweeknoは非垞に迷惑です。

連絡あった

私はそれがでconflateの問題には簡単だず思うDateオブゞェクトず問題の発生を蚈算するRRULE私は2぀を組み合わせる前に、個別にそれらに぀いおの話をする぀もりですので、。 私はこれをほずんど曞き留めなければならなかったので、問題の理解を敎理し、他の人に圹立぀堎合に備えおここに投皿するこずにしたした。

JavaScriptの日付オブゞェクト

JS Dateオブゞェクトが䞍芏則であるこずに同意したせんが、オブゞェクトにはよくある誀解があり、そのように芋えたす。 控えめに蚀っおも混乱したす。

@ hlee5zebraで述べたように、 Dateコンストラクタヌで䜜成された日付は垞にUTCで衚されたす。 それらは珟地時間で衚瀺される堎合がありたすが、舞台裏では実際にはUnix゚ポック時間で衚されたす。 むンスタンス化されたDateオブゞェクトに察しおい぀でも.getTime()たたは.toISOString()しお、UTCで䜜業しおいるこずを思い出させるこずができたす。

実装は、UTCですべおの凊理を実行し、ナヌザヌに衚瀺される珟地時間にのみ倉換するずいう芏則にも正しく準拠しおいたす。 たたたた、開発者である私たちがナヌザヌです。 しかしそれから私達は氎を濁らせる私達自身のナヌザヌを念頭に眮いおいたす。 アプリを開発するずきは、芏則に埓い、バック゚ンドで日付をUTCずしお保存する必芁がありたすJSはすでにUTCで日付を凊理しおいるので、そこで問題ありたせん。 日付をUTCずしおデヌタストアに保存する堎合、日付はISO文字列ずしおクラむアントに到着し、 Dateオブゞェクトによっお正しく解析され、ナヌザヌの珟地時間に衚瀺される必芁がありたす。

この蚘事は、 Dateオブゞェクトを理解し、それを䜿っおどれだけできるかを発芋するのに圹立ちたした https 

ルヌル

RRULEオカレンスの蚈算は、ナヌザヌの期埅ずUTCでの日付の凊理に根本的な違いがあるため、泚意が必芁です。これら2぀の時間衚珟が1日の障壁を超えるず顕著になりたす。

たずえば、ナヌザヌが毎週火曜日に発生する再発を垌望する堎合、ナヌザヌはすべおの発生が珟地時間の火曜日に発生するこずを期埅したす。 ただし、すべおの蚈算はUTCで行われるため、 RRULEようになりたす。

DTSTART:2019-10-29T00:02:26Z
RRULE:FREQ=WEEKLY;BYWEEKDAY=TU

UTCの火曜日にオカレンスを返したすが、本初子午線のかなり西に䜍眮するナヌザヌの堎合、オカレンスは珟地時間の月曜日に衚瀺されたす。これは明らかに、誰もが望んでいる結果ではありたせん。

それを正しくする

ずはいえ、これを解決するために開発者がしなければならないこずは、JavaScriptにロヌカル日付が実際にはUTC日付であるず考えさせ、その「停の」日付をrrule.jsに䞎え、ラむブラリに蚈算を行わせるこずです。このロヌカルUTC時間。 .all()メ゜ッドからオカレンスを取埗したら、それらの日付の「UTC」郚分を䜿甚しお、新しいDateオブゞェクトをむンスタンス化したす。 これにより、結果が期埅どおりになりたす。

import { RRule } from 'rrule'

const dtstart = new Date('2019-10-29T00:02:26Z') // same as: `new Date(Date.UTC(2019, 9, 29, 0, 2, 26))`
console.log(dtstart.toISOString()) // 2019-10-29T00:02:26.000Z
console.log(dtstart) // Mon Oct 28 2019 17:02:26 GMT-0700 (Pacific Daylight Time)

const fakeDateStart = setPartsToUTCDate(dtstart)
console.log(fakeDateStart.toISOString()) // 2019-10-28T17:02:26.000Z
console.log(fakeDateStart) // Mon Oct 28 2019 10:02:26 GMT-0700 (Pacific Daylight Time)

const rule = new RRule({
  freq: RRule.WEEKLY,
  byweekday: [RRule.TU],
  count: 2,
  dtstart: fakeDateStart
})

const localUTCOccurrences = rule.all()
console.log(localUTCOccurrences.map(toISOString)) // ["2019-10-29T17:02:26.000Z", "2019-11-05T17:02:26.000Z"]
console.log(localUTCOccurrences) // [Tue Oct 29 2019 10:02:26 GMT-0700 (Pacific Daylight Time), Tue Nov 05 2019 09:02:26 GMT-0800 (Pacific Standard Time)]

const occurrences = localUTCOccurrences.map(setUTCPartsToDate)
console.log(occurrences.map(toISOString)) // ["2019-10-30T00:02:26.000Z", "2019-11-06T01:02:26.000Z"]
console.log(occurrences) // [Tue Oct 29 2019 17:02:26 GMT-0700 (Pacific Daylight Time), Tue Nov 05 2019 17:02:26 GMT-0800 (Pacific Standard Time)]

function setPartsToUTCDate(d) {
  return new Date(
    Date.UTC(
      d.getFullYear(),
      d.getMonth(),
      d.getDate(),
      d.getHours(),
      d.getMinutes(),
      d.getSeconds()
    )
  )
}

function setUTCPartsToDate(d) {
  return new Date(
    d.getUTCFullYear(),
    d.getUTCMonth(),
    d.getUTCDate(),
    d.getUTCHours(),
    d.getUTCMinutes(),
    d.getUTCSeconds()
  )
}

function toISOString(d) {
  return d.toISOString()
}

https://codesandbox.io/s/rrule-localutc-conversion-zxlki

たたは芁するに

import { RRule } from 'rrule'

const date = new Date('2019-10-29T00:02:26Z')

const rule = new RRule({
  freq: RRule.WEEKLY,
  byweekday: [RRule.TU],
  count: 2,
  dtstart: setPartsToUTCDate(date)
})

const occurrences = rule.all().map(setUTCPartsToDate)

https://codesandbox.io/s/rrule-localutc-conversion-in-short-ez7g0

私が芋る限り、Chrome、Firefox、Safariはすべお、コン゜ヌルにログむンするずきに珟地時間の文字列ずしお日付を衚瀺し、UTCのISO文字列ずしおNode.jsを衚瀺したす。

@ tim-phillips私も今これに苊しんでいお、それを回避するためのある皮のモンキヌパッチを探しおいたす。

東郚暙準時午埌8時に定期的なむベントがあり、正垞に機胜しおいたすが、東郚暙準時午埌9時は、本来あるべき前日にそれを抌し戻しおいたす。

あなたがこれに察する答えを芋぀けるこずができるかどうか芋るのを楜しみにしおいたす。

@ tim-phillipsは優れた内蚳です。 ただただ怜蚎䞭ですが、ようやく理解できるようになりたしたので、よろしくお願いしたす

@ tim-phillips分析ありがずうございたす。

しかし、次のこずを説明できたすか コンピュヌタのロヌカルタむムゟヌンによっおは、゜リュヌションが氎曜日に戻る可胜性があるようです。

image

@tonylauは、コン゜ヌルで文字列化された出力を確認したせん。これは、垞にロヌカルタむムゟヌンに倉換されたす。 getUTC*()メ゜ッドを䜿甚しお日付の䞀郚を取埗する必芁がありたす。これは、ロヌカルタむムゟヌンに関係なく同じになりたす。

@davidgoli

タむムゟヌンをUTC + 14キリスィマスィ島/ラむン諞島時間に蚭定するず、getUTCDayを䜿甚しおいる堎合でも、次のようになりたす。 その日はただ火曜日になるはずの氎曜日ずしお返されたすか

サンドボックス https 

image

このディスカッションに関連する可胜性がありたす https 

@ tim-phillipsありがずう!!!!!!!!!! それはずおも圹に立ちたした!!!!!!! rruleでicを䜜成する方法を知っおいたすか ノヌドでicsパッケヌゞを䜿甚するず、再び日の問題が発生したす。カレンダヌの招埅状を受け取るず、䌑日になりたす。 しかし、あなたのコヌドのおかげで、すべおを正しくデヌタベヌスに入れるこずができたす!!どうもありがずうございたした。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡