问题
I am using date-fns to format dates
If I pass a date that ends in Z, it knows that it is UTC, and I can format(date, "yyyy-MM-dd")
and it will be in local computer time.
If the date I want to express in local computer time is originally CST, is there something to add at the end instead of the Z, that will be understood by the format function as a CST date?
Sorry if this is a bad question
Edit: is there a way to do zonedTimeToUtc(myDate, 'UTC-6')
in date-fns? (instead of using a time zone name)
回答1:
If you have a string that you always want parsed as CST (US central standard time) using date-fns, you can include date-fns-tz and set the timezone when parsing (I've assumed an ISO 8601 loose format without the timezone). Note that to avoid DST, you have to pick a location that is UTC-6 all year round, e.g. Canada/Saskatchewan.
// Setup
var {parse} = require('date-fns');
var {zonedTimeToUtc, utcToZonedTime, format } = require('date-fns-tz');
// Parse using location for offset
let loc = 'Canada/Saskatchewan';
let s = '2020-08-14 13:05:52';
let fIn = 'yyyy-MM-dd HH:mm:ss';
let utcDate = zonedTimeToUtc(s, loc);
// Show local equivalent
console.log(utcDate);
This leaves you somewhat at the mercy of the administrators of Saskatchewan, who might change the offset or introduce DST. An alternative is to append the exact offset you want to the timestamp and include it in the parse tokens:
// Parse using string for offset
let tz = '-06';
let utcDate2 = parse(s + ' ' + tz, fIn + ' X', new Date());
// Show local equivalent, should be same as above
console.log(utcDate2);
The advantage of the second method is that it doesn't require date-fns-tz and you aren't beholden to historic or future changes to Saskatchewan's offset (or that of any other IANA location).
Apparently there is a UTC module in development that will allow setting specific offsets like -6 rather than using IANA locations (can't find a link to that comment atm).
At this point the string has been parsed as GMT-6, but is still just a plain Date (i.e. just a time value with no idea of the timezone that was associated with the original string).
Once you have the date you can then show it as CST for output. To use an IANA location for the offset in call to format, you have to use format from date-fns-tz, not plain date-fns, otherwise it will just use the host system offset.
Note that the value in the format call is just setting the value to use for the offset string, it doesn't do anything to the actual date and time, that adjustment has already been applied by utcToZonedTime.
// Adjust to CST
let dCST = utcToZonedTime(utcDate2, loc);
// Format strings:
let fOut1 = 'yyyy-MM-dd HH:mm:ss XXX'; // -0600
let fOut2 = 'yyyy-MM-dd HH:mm:ss z'; // CST
// Format using location
console.log(format(dCST, fOut1, {timeZone: loc}));
console.log(format(dCST, fOut2, {timeZone: loc}));
I prefer the -0600 version as it avoids questions of whether DST is observed or not (and is really what the code is doing). Also, in the "z" version you might get the offset or the timezone name (probably depending on the host default language and location, which is a quirk of date-fns-tz using Intl.DateTimeFormat I think).
You can also manually add the timezone using a format string like:
let fOut = 'yyyy-MM-dd HH:mm:ss \'-0600\'';
which will produce an output like:
"2020-08-14 13:05:52 GMT-0600"
I don't think there is any way to set a specific offset like "-0600" for both parsing and formatting without including it in the call. I think moment.js and luxon allow it.
For completeness, here's some code you can run at npm.runkit.com since there's no CDN for the current date-fns version to allow the code to run here.
var {parse} = require('date-fns');
var {zonedTimeToUtc, utcToZonedTime, format } = require('date-fns-tz');
// Parse using location for offset
let loc = 'Canada/Saskatchewan';
let s = '2020-08-14 13:05:52';
let fIn = 'yyyy-MM-dd HH:mm:ss';
let utcDate = zonedTimeToUtc(s, loc);
// Show local equivalent
console.log(utcDate);
// Parse using string for offset
let tz = '-06';
let utcDate2 = parse(s + ' ' + tz, fIn + ' X', new Date());
// Show local equivalent, should be same as above
console.log(utcDate2);
// Format using location:
let fOut1 = 'yyyy-MM-dd HH:mm:ss XXX'; // -0600
let fOut2 = 'yyyy-MM-dd HH:mm:ss z'; // CST
let dCST = utcToZonedTime(utcDate2, loc);
console.log(format(dCST, fOut1, {timeZone: loc}));
console.log(format(dCST, fOut2, {timeZone: loc}));
回答2:
Try using moment libraries to solve your time problems: moment.js, and its complement moment-timezone.js
To output the current time converted to CST timezone:
moment().tz('America/Chicago').format('hh:mm:ss z')
06:43:34 CST
moment().tz('America/Chicago').format('hh:mm:ss z Z')
06:43:35 CST -06:00
moment().tz('America/Chicago').format()
2020-08-13T15:52:09-06:00
Or maybe use a function as below:
const calcTime = (cityOffset) => {
var now = new Date();
// convert to msec and add local time zone offset and get UTC time in msec
var utc = now.getTime() + (now.getTimezoneOffset() * 60000);
// create new Date object for different city using supplied offset
var newTime = new Date(utc + (3600000 * cityOffset));
return newTime.toLocaleString();
}
来源:https://stackoverflow.com/questions/63385910/express-time-as-cst-in-javascript-date-fns