New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
date-fns-tz v2 proposal #36
Comments
I think that JS Date actually always UTC (because it only stores timestamps inside) and it appears as it is in system time zone because when you call |
I think reasoning about shiftDateTo(date, timeZone)Shift For example, if in Australia (AEDT) const fiveAm = new Date('2019-12-29 05:00') // 5am in local time
const result = shiftDateTo(fiveAm, 'Asia/Tokyo')
// result is 3am in local time (Australia), 5am in Tokyo unshiftDateFrom(date, timeZone)Unshift const fiveAm = new Date('2019-12-29 05:00') // 5am in local time
const result = unshiftDateFrom(fiveAm, 'Asia/Tokyo')
// result is 7am in local time (Australia), 5am in Tokyo That way, the following identity should hold const a = new Date('2019-12-29 05:00') // 5am in local time
const b = shiftDateTo(a, 'Asia/Tokyo') // 3am in local time
const c = unshiftDateFrom(b, 'Asia/Tokyo') // 5am in local time edit: renamed again |
@dcousens why would you shift date in the first place? Isn't it easier to just pass a time zone whe you parse string date like |
@kroleg I'll try and outline a few scenarios. Scenario 1Imagine we have a server in const lastPostedAt = new Date(user.posts[0].createdAt)
const local11am = new Date()
local11am.setHours(11)
local11am.setMinutes(0)
local11am.setSeconds(0)
local11am.setMilliseconds(0)
const users11am = shiftDateTo(local11am, user.timezone)
if (lastPostedAt > users11am) {
// the last post was after 11am user-time on this calendar day
} Scenario 2For a second scenario, I have a friend in San Francisco that has provided me with a date and time string I need to know what the local time for that web meeting would be so I can attend. const provided = new Date(`2019-12-30 14:00`)
const local = unshiftDateFrom(provided, `US/Pacific`)
// local is 9am on Tuesday 31st October (local time) Arguably, yes, the second scenario could use |
@dcousens for scenario 1 there is a much easier way to get local time: const local11am = parseFromTimeZone('11:00', user.timezone); And then you compare Date instances Edit: As i mentioned above |
@kroleg I don't always use today's calendar date. I don't want to transform a |
@dcousens you gave me 2 problems and i told you how you can solve them with only 2 functions. Do you have another problems/secenarios you forgot to mention?
then pass full datetime like |
You actually haven't provided 2 solutions, you've merely pointed at a string-parsing equivalent of Please post a working solution for when you have a |
Thank you both for the discussion so far. I believe it makes sense to have functions for shifting Date instances as well as functions with string input/outputs, i.e. parse and format. Firstly, the former is a requirement to implement the latter and as such might as well be exposed as low level functions for use when it makes sense. Aside from the examples given by @dcousens (which might be implementable starting/ending with strings, but depending on preference in a less elegant way), a further issue would be use alongside other libraries. Most notably date picker elements often take Date instances as input/output, so it must be possible to work with Dates. I like the idea of not having aliased functions but rather two shifting functions that don't reference local/UTC if that is confusing (and I agree it can be). The suggestions are good, and I'll give the names a bit more thought. Other than those I'm starting to like the idea of then overriding the |
I somehow failed to convey that this is exactly the scenario as to why strings were not suitable 👍 - 3rd party libraries. |
vs
The time zone must be specified twice, which is overly verbose. Correct me if I'm wrong. |
I'd love I'd like to add my two cents about the shifting functions. Even though the shifting logic is necessary to use JavaScript's I do understand @dcousens's argument that these functions could be useful for integrating with other libraries. In my opinion, it would be less confusing if they were clearly marked as a more of a plumbing API rather than the primary API of An alternative approach would be to provide a wrapper class around |
Thanks for your thoughts @jgonera. The point about renaming I don't think I'll put the shifting functions in a separate |
I'm just starting to use date-fns[-tz] and I love all of it ❤️ except I agree there are low-level use cases for the 2nd "calendar" meaning, I just wish the API was shaped differently so code using the 1st vs 2nd meaning look different... Actually, in a sense the base
|
Thinking/reading more about it, I see many functions in |
Agree @cben a date is a moment in time that accounts for DST as well. moment can handle ISO8601 timestamps with offset such as I would expect a date library to format that timestamp into a specific timezone that was passed in as a 2nd parameter. |
How would one go about parsing a date string with a known format zoned to a known TZ? Please correct me if I'm wrong but, as I understand it, there's not built-in way (neither in the current version or the proposed v2 API) to do this. Here's how you would accomplish this in other popular date handling libraries: // dayjs using `timezone` plugin
dayjs.tz("11-20-2020", "America/Los_Angeles").format();
// '2020-11-20T00:00:00-08:00' // moment using `moment-timezone`
moment.tz('11-20-2020', 'MM-DD-YYYY', 'America/Los_Angeles').format();
// '2020-11-20T00:00:00-08:00' DateTime.fromFormat('11-20-2020', 'MM-dd-yyyy', { zone: 'America/Los_Angeles' }).toISO();
// '2020-11-20T00:00:00-08:00' IMHO, this is a fairly basic use case scenario when it comes to timezones and |
@nfantone the functionality you are after is possible by using the import {parse} from 'date-fns'
import {format, zonedTimeToUtc} from 'date-fns-tz'
const dateForLA = parse('11-20-2020', 'MM-dd-yyyy', new Date()) // new Date is a required arg but ignored, see date-fns#2849
// We know this date represents the time in LA, so it is passed to format as is,
// with the `timeZone` needed to get the correct value for the xxx token
const output = format(dateForLA, 'yyyy-MM-dd\'T\'HH:mm:ssxxx', { timeZone: 'America/Los_Angeles' })
console.log(output) // 2020-11-20T00:00:00-08:00
// If you want to send the proper UTC time to a server or save to a database, use
const date = zonedTimeToUtc(parsed, 'America/Los_Angeles')
console.log(date.toISOString()) // 2020-11-20T08:00:00.000Z The question is whether there is a way to make this more intuitive. Edit: After thinking about it this is probably the proper way of doing it in v2: import {parse, formatAsZonedTime} from 'date-fns-tz'
// or parseAsZonedTime?
const date = parse('11-20-2020', 'America/Los_Angeles', 'MM-dd-yyyy')
console.log(date.toISOString()) // 2020-11-20T08:00:00.000Z
const output = formatAsZonedTime(date, 'America/Los_Angeles', 'yyyy-MM-dd\'T\'HH:mm:ssxxx')
console.log(output) // 2020-11-20T00:00:00-08:00 |
@marnusw Hi! Thanks for your answer. May be so - honestly, it's been over a year since I posted the above. Regardless, the fact that you even had to think about how to go about parsing a zoned data kinda goes in the same line as my original point. |
@nfantone O I see. When I looked at it I thought it was this past October. Thank you for your input, though, it has made me think and contributes toward the final API. |
Not sure if it's possible now, get GMT version of timezone offset: I believe it's |
@vladshcherbin use |
@marnusw the thing is, I only have a timezone, just Maybe there could be a simple helper for such things, e.g. What do you think? |
Africa/Casablanca is a timezone. +01:00 is an offset. |
Timezones change their offsets over time, regularly due to daylight-savings, and irregularly due to political decisions...
So a simple mapping TZ->offset is ill-defined. You can pass |
These are the proposed functions for
date-fns-tz
version 2. Comments are welcome.parseUTC
Parse a date string representing UTC time to a
Date
instance. This is a reexport ofdate-fns/parseJSON
with a more semantically relevant name.localToZonedTime
Transform a
Date
instance in the local system time zone, i.e. when it is passed toformat
it would show the local time, to a zonedDate
instance of the target time zone, i.e. when passed toformat
it would show the equivalent time in that time zone.This is achieved by modifying the underlying timestamp of the
Date
. In other words, since a JSDate
can only ever be in the system time zone, the way to fake another time zone is to change the timestamp.Matching the convention set by
date-fns
this function does not accept string arguments. A date string should be parsed withparseUTC
,parseISO
orparse
first.zonedToLocalTime
Transform a
Date
instance representing the time in some time zone other than the local system time zone to aDate
instance with the equivalent value in the local system time zone, i.e. formatting the result or calling.toString()
will show the equivalent local time.This is achieved by modifying the underlying timestamp of the
Date
. It is the inverse oflocalToZonedTime
, so in this case it is assumed the input is faking another time zone, and the timestamp is changed to be correct in the current local time zone.Matching the convention set by
date-fns
this function does not accept string arguments. A date string should be parsed withparse
first.utcToZonedTime
This is an alias of
localToZonedTime
which can be used when it makes better semantic sense, such as when a UTC date received from an API is being parsed for display in a targed time zone. Since a UTC time will usually be provided as a string value, this function accepts UTC date strings that can be parsed by theparseUTC
function and does so internally.zonedTimeToUTC
This is an alias of
zonedToLocalTime
which can be used when it makes better semantic sense, such as when the intent is to save the UTC time of a date to an API. The resultingDate
which formats correctly in the system time zone has the desired internal UTC time, and thus the actual UTC value can be obtained fromzonedTimeToUTC(...).toISOString()
or.getTime()
.format
Full time zone formatting support, without any modification to the date instance. (No changes from
format
in v1, except that it will no longer accept string inputs.)formatAsZonedTime
A combination of
utcToZonedTime
(orlocalToZonedTime
) andformat
. In other words the date will be transformed to the target time zone specified in the options prior to formatting. SinceutcToZonedTime
is used internally the date argument can also be a string that can be parsed byparseUTC
.parseISO
As in
date-fns
the previous implementation oftoDate
indate-fns-tz@1
has been renamed toparseISO
. It extends thedate-fns
version of this function with better time zone support. It is a rather large function, though, and should only be used when dates are not in ISO format or date strings represent a time zone other than UTC time. When this is not the caseparseUTC
should be used instead.@dcousens, @kroleg
The text was updated successfully, but these errors were encountered: