问题
I would like to calculate the current local time when it's 24:00 the next day in Los Angeles. The purpose is to set a cookie until the next midnight in la.
I have used moment and moment timezone, however, I can't justify the overhead to the build size for a single function.
Here is what I am working with but I'm stuck on converting the time from LA midnight back to the local time as when i convert back it's before the current time. I don't think there will be an issue with the convertToOtherTimezone function when reversing but I'm not too sure what else to explore.
Any help is greatly appreciated.
const convertToOtherTimezone = (date, from, to) => {
const utc = date.getTime() + (3600000 * from)
return new Date(utc + (3600000 * to))
}
console.log(
'native local time in LA',
new Date().toLocaleString('en-US', { timeZone: 'America/Los_Angeles' })
)
const LA_OFFSET = -7
// I'm using the AEST timezone -10
const LOCAL_OFFSET = new Date().getTimezoneOffset() / 60
const midnightInLA = (localOffset) => {
// get the current time in LA
const la = convertToOtherTimezone(new Date(), localOffset, LA_OFFSET)
console.log('current time in LA', la)
// set date to midnight in LA's timezone
la.setHours(24,0,0,0)
console.log('next midnight in LA', la)
// convert back to local time
return convertToOtherTimezone(la, LA_OFFSET, localOffset)
// Ulias Hunka gave the correct answer, but deleted his post.
// reverse the offsets
return convertToOtherTimezone(la, LA_OFFSET * -1, localOffset * -1)
}
console.log(
'la midnight in local time',
midnightInLA(LOCAL_OFFSET)
)
<script src="https://codepen.io/synthet1c/pen/KyQQmL.js"></script>
回答1:
I believe that the snippet in your question is quite close but it appears that you are adding the offset in the wrong direction.
You might encounter problems with daylight savings time - for instance, LA is at UTC-7h during the summer months but UTC-8h normally. If you don't want to use moment.js then the only option I can think of is to parse a locale-formatted string of the time.
This is not the most robust method and will only work (as is) for en-US formatted times. The America/Los_Angeles timezone might also not be available depending on the browser.
let now = new Date()
// Get the current time in LA using string matching to enable the offset to be calculated
// This allows for daylight savings to be considered
// Caution the LocaleTimeString is en-US formatted. Take care if using a different locale
let timeInLA = now.toLocaleTimeString('en-US', { timeZone: 'America/Los_Angeles' })
.match(/([0-1]?[0-9])\:([0-5]?[0-9])\:[0-5]?[0-9]\s(AM|PM)/)
// trim first element of match
.slice(1)
// take account of AM/PM and convert values to integers
.map( (e,i,a) => i==0 && a[3] =='PM' ? +e+12 : +e)
// trim AM/PM
.slice(0,-1)
// positive values mean local time is ahead of LA
let offsets = [now.getHours(),now.getMinutes()].map((e,i) => e-timeInLA[i])
// sum up hours and minutes to get totalOffset and convert to ms
let totalOffsetMS = (offsets[0]*3600 + offsets[1]*60)*1000
// local midnight Tomorrow - add 24 hours and zero other values
let localMidnightTomorrow = new Date(+now.setHours(24,0,0,0))
// LA midnight will happen at the local midnight time with the offset added
let localTimeWhenMidnightInLA = new Date(+localMidnightTomorrow + totalOffsetMS)
console.log(`It will be "${localTimeWhenMidnightInLA.toDateString()} ${localTimeWhenMidnightInLA.toTimeString()}" in your location when it is midnight in LA tomorrow`)
回答2:
Los Angeles standard time is UTC-0800. It changes into daylight saving time (DST) at 2am on the second Sunday in March when the offset changes to UTC-0700. It ends at 2am (DST) on the first Sunday in November.
It is likely that these rules will persist for some time into the future, and if you're only interested in present dates, you can use these rules until they change. You can work out the offset for a given date and time, then create a date for the next midnight in LA. I wish you had put that information in the question and not in comments. See below.
/**
* Calculate the offset in LA for the given date and time.
* LA DST starts on the second Sunday in March at
* 10:00 UTC. After that, the offset is UTC-0700
* LA DST ends on the first Sunday in November at 09:00
* UTC. After that the offset is UTC-0800
*
* @param {Date} date - date object
* @returns (boolean} true if DST is being observed
*/
function getLAOffset(date) {
// Get DST start in UTC
var start = new Date(Date.UTC(date.getUTCFullYear(), 2, 1, 10));
start.setUTCDate(start.getUTCDate() + (7-start.getUTCDay())%7 + 7);
// Get DST end in UTC
var end = new Date(Date.UTC(date.getUTCFullYear(), 10, 1, 9));
end.setUTCDate(end.getUTCDate() + (7-end.getUTCDay())%7);
return (date >= start && date < end)? -7 : -8;
}
/** Return a Date object set to midnight in LA
* for the next midnight after the given date.
* Offset comes from getLAOffset
*
* @param {Date} date to use for local date values
* @returns {Date} set to midnight in LA
*/
function getLAMidnight(date) {
var d = new Date(+date);
// Get offset. If hour is before offset, set to offset
// If hour is after offset, set to offset tomorrow
// Re-check offset and adjust if necessary
var offset = getLAOffset(d);
var midLA = d.setUTCHours(-offset, 0, 0, 0);
if (d < date) d.setUTCDate(d.getUTCDate() + 1);
d.setUTCHours(-getLAOffset(d));
return d;
}
// Local date and time for midnight LA tomorrow:
[new Date(2018,0, 1), // 1 Jan 2018
new Date(2018,2,11), // 11 Mar 2018
new Date(2018,2,11, 12), // 11 Mar 2018, noon
new Date(2018,2,12), // 12 Mar 2018
new Date(2018,5, 1), // 1 Jun 2018
new Date(2018,10,4), // 4 Nov 2018
new Date(2018,11,1), // 1 Dec 2018
new Date() // Current
].forEach(function(date) {
console.log('Local date : ' + date.toString() +
'\nNext LA midnight : ' + getLAMidnight(date).toString());
});
来源:https://stackoverflow.com/questions/51263321/js-get-the-local-time-at-midnight-for-a-different-timezone