Time in Known Location with Known Offset and NO Daylight Saving Time - javascript

With the hundreds of posts concerning Javascript time questions, I'm certain this has been addressed but I've been through a couple of dozen posts so far and none answer my specific question. I know the offset (-7) and in this particular State in the USA (Arizona) there is NO DST. I just want to display the time in Arizona to any user. All the posts I've reviewed seem to imply that I need to use
return new Date().getTimezoneOffset();
from the local computer as part of my calculations but I'm not sure why that would be necessary? Would this be a viable solution?
const now = new Date();
return {
hour: (now.getUTCHours() -7)
minute: now.getMinutes(),
};

There is no DST in Arizona presently, but that doesn't mean there never will be. Sure, unlikely - but not impossible.
A more robust solution, which also accounts for locale formatting preferences of the user, is as follows:
const s = new Date().toLocaleTimeString(undefined, {
timeZone: 'America/Phoenix'
});
console.log(s);
This will work with any IANA time zone identifier, accounting for DST when applicable, or not - depending on the time zone.
If you want the exact output as in your question, try something like this:
const s = new Date().toLocaleString('en', {
timeZone: 'America/Phoenix',
hour12: false,
hour: 'numeric',
minute: 'numeric'
});
const p = s.split(':');
const o = {
hour: parseInt(p[0]),
minute: parseInt(p[1])
};
console.log(o);

You do not need to getTimezoneOffset, but you will need to handle the case when the hours are smaller than 7:
const now = new Date();
console.log( {
hour: ((now.getUTCHours() -7) % 24),
minute: now.getMinutes(),
});

You can use the Intl object and Etc pseudo–timezone for a fixed offset. The EMCAScript version only supports whole hour offsets and the sign is the reverse of convention.
E.g.
console.log('Current time in UTC-7: ' +
new Date().toLocaleString('default',{timeZone:'Etc/GMT+7', hour:'numeric', minute:'2-digit'})
);
console.log('Current time in UTC-7: ' +
new Date().toLocaleTimeString('default',{timeZone:'Etc/GMT+7'})
);

Related

Converting to local time using UTC time zone format in Javascript

Been trying to wrap my head around this for a good time now, but I can't think of a good way to do it.
I have an array with a bunch of different UTC time zones (in just format -07, -01, +03, +10, etc). What I'm trying to achieve is a way to show the local time of those time zones, possibly including the day and month.
Here's an example of the resulting string: Local time: 14:09 23/08
You can use Date.prototype.getTimezoneOffset() to get your local timezone. Calculate the difference between your local timezone and the destination timezone, multiply it with 3600000 and add it to a Date object containing the current time.
const now = new Date();
const timezoneOffset = now.getTimezoneOffset() / 60;
const timezones = ['-07', '-01', '+03', '+10'];
timezones.forEach(timezone => {
const difference = +timezone + timezoneOffset;
const time = new Date(now.getTime() + difference * 3600000);
console.log(`Local time: ${time.toLocaleTimeString([], { timeStyle: 'short', hour12: false })} ${time.toLocaleDateString([], { month: '2-digit', day: '2-digit' })}`);
});

How do I convert certain Date object to the corresponding time in germany? [duplicate]

This question already has answers here:
Convert date to another timezone in JavaScript
(34 answers)
Closed 2 years ago.
Let's say I have a Date object like this:
let dateToConvert = new Date(date_string) // represents certain time like 12th Aug 11PM in India
What I want to achieve is to design a function like this:
getGermanDate(dateToConvert): Date {
// What should be written here?
}
The function should return Date object that is the time in Germany at the time that is in dateToConvert object.
Thanks in advance.
Formatting of javascript dates is covered in numerous other questions. A particular timezone can be specified using the timeZone option with toLocaleString or for more control use the Intl.DateTimeFormat constructor and format option (timezones are specified using an IANA representative location to apply historic and DST changes), e.g.
let d = new Date();
// toLocaleString, default format for language de
console.log(d.toLocaleString('de',{timeZone:'Europe/Berlin', timeZoneName: 'long'}));
// DateTimeFormat.format with specific options
let f = new Intl.DateTimeFormat('de', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
hour12: false,
minute: '2-digit',
timeZone: 'Europe/Berlin',
timeZoneName: 'short'
});
console.log(f.format(d));
You might also be interested in this answer.
You could use native JavaScript functions to convert (toLocaleString), or you could use moment timezone (which is more flexible).
For the toLocaleString call I'm also specifying a Germany date format (by passing "de-DE" to the locale parameter, you could use whichever locale you wish.
function getGermanDate(input) {
return moment.tz(input, "Europe/Berlin");
}
/* Using moment timezone */
let timestamp = "2020-08-12 23:00:00";
let timeIndia = moment.tz(timestamp, "Asia/Kolkata");
let timeGermany = getGermanDate(timeIndia);
console.log("Time (India):", timeIndia.format("YYYY-MM-DD HH:mm"));
console.log("Time (Germany):", timeGermany .format("YYYY-MM-DD HH:mm"));
/* Using native JavaScript */
let dateToConvert = new Date("2020-08-12T23:00:00+0530");
console.log("Time (India, native):", dateToConvert.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' }));
console.log("Time (Germany, native):", dateToConvert.toLocaleString('de-DE', { timeZone: 'Europe/Berlin' }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.25/moment-timezone-with-data-10-year-range.js"></script>

How do I compare a JavaScript date against a date in a specific timezone?

I want to see if the current time is greater than Monday of this week at 5:00 pm mountain time, no matter what timezone this code is running in. I've got something like this:
function isAfterMondayEvening() {
var now = new Date();
var mondayEvening = dateFns.setHours(dateFns.setDay(now, 1), 17);
return dateFns.compareAsc(now, mondayEvening);
}
console.log(isAfterMondayEvening());
<script src="//cdn.rawgit.com/date-fns/date-fns/a0005af7d1c3f70c88b8e619bfdff4bf85122863/dist/date_fns.js"></script>
If the server or browser this is running in is in a different timezone, then it will compare the time to Monday at 5 in their timezone. I want to to be compared to Monday at 5 pm in mountain time, no matter what timezone this code runs in. How I can do this?
A method I have used is to normalize both dates to GMT. Assuming your server date is in GMT already, you can convert the browser time to GMT by subtracting the timezone offset.
For example, I am in Atlantic Standard Time (GMT+4). To get the current time as if I was in GMT, I use the formula:
2018-02-09T15:00:00+0400 - (4 * 60 * 60 * 1000) = 2018-02-09T15:00:00Z`
...where 4 is the offset in hours.
Specifically in JS:
const browserOffset = new Date().getTimezoneOffset();
const timeFromServer = getTimeFromServer();
const currentTimeAsGmt = new Date(Date.now() - (browserOffset * 60 * 1000));
// Now compare timeFromServer (already in GMT) to currentTimeAsGmt
In JS, Date#getTimezoneOffset returns the offset in minutes so I omit an extra * 60.
If you are cool with IE 10+, use luxon (https://moment.github.io/luxon/index.html)
function isAfterMondayEvening() {
const currentTime = luxon.DateTime.local().setZone('America/Denver');
const mondayEvening = currentTime.set({weekday: 1, hour: 17}).startOf('hour');
return currentTime > mondayEvening;
}
Assuming you can figure out this week's Monday year/month/day indexes, I think you can do this without libraries. The trick is to represent your known Mountain time in terms of UTC:
let utcMonday = new Date(Date.UTC(2018, 2 - 1, 5, 24));
let cstDate = new Date();
let currentTimeGreater = cstDate > utcMonday;
// The rest isn't needed, but shows some console logs of what is going on
let locale = "en-US";
let timeFormatOptions = {
weekday: "short",
hour: "numeric",
minute: "numeric",
timeZoneName: "long",
timeZone: "America/Denver"
};
let formattedMountainMonday = utcMonday.toLocaleDateString(
locale,
timeFormatOptions
);
let formattedCurrentTime = cstDate.toLocaleDateString(
locale,
timeFormatOptions
);
console.log(formattedMountainMonday);
console.log(
`Current time in relation to Mountain time: ${formattedCurrentTime}`
);
console.log(
`Current time is greater than this week's Mountain Monday at 5:00 PM: ${currentTimeGreater}`
);
The US Mountain Time (MT) offset is -0700. Javascript dates are UTC at heart, so all you need to do is compare the internal UTC time value to MT. By "Monday of this week" I presume you want true for Sunday and Monday up to 17:00. If you just mean Monday, then remove the d.getUTCDay() == 0 || part.
function isBefore1700MT(date) {
// Copy date so don't affect original
var d = new Date(date);
// Adjust internal UTC to MT
d.setUTCHours(d.getUTCHours() - 7);
// Return true if the UTC day is Sunday or Monday before 17:00
return d.getUTCDay() == 0 || (d.getUTCDay() == 1 && d.getUTCHours() < 17);
}
// Test using current local date and time
var date = new Date();
console.log(date.toString() + ' : ' + isBefore1700MT(date));
When you say "mountain time", are you always talking about Mountain Standard Time or are you wanting to account for Mountain Daylight Time as well? If you're always talking about Mountain Standard Time, you can ignore my answer since your case is simpler. I'm going to address the possibility that you want to account for Mountain Daylight Time as well, which is a more complex problem.
If you're taking daylight time into account, keep in mind that not every place inside the Mountain Time zone observes Mountain Daylight Time, so you actually need to know the location inside the Mountain Time zone (e.g., is it Arizona or Utah?). Once you know that, you need a library like Moment Timezone that has adequate time zone information. You then have to find the most accurate tz database timezone name and use it, with the help of Moment Timezone to figure out the actual UTC time for "Monday of this week at 5:00 pm mountain time in this particular location". Your code would look something like this:
// Use whatever time and timezone you're trying to compare with.
const targetDate = moment()
.tz('America/Denver')
.day(1) // Monday
.hour(17) // 5pm
.minute(0)
.second(0)
.millisecond(0)
.toDate();
if (new Date() > targetDate) {
console.log('after target time');
} else {
console.log('before target time');
}

get timezone offset of another timezone in javascript without using Strings

I want to calculate the offset from 'users time' to 'WET/WEST'.
I get the users offset with new Date().getTimezoneOffset().
But how do I get the offset for WET/WEST So that I can calcluate the combined offset of both?
For example, if the user is in central europe time (CET/CEST), in winter the combined offset would be -60 (CET) + 0 (WET) = -60. In summer, it would be -120 (CEST) + 60 (WEST) = -60. In this case it is always -60 but the user could also have a timezone without DST.
Is this possible without format it to a string and read out the new timezone from that string?
You can't use time zone abbreviations reliably for input, as they can be interpreted in many different ways. For example, CST might be either "Central Standard Time" in North America, or "China Standard Time", or "Cuba Standard Time". While some abbreviations like WET and WEST are unique, many are ambiguous. Refer to the list of time zone abbreviations here.
Instead, you need to know the IANA time zone identifier. One location that uses WET/WEST is Portugal, which as the IANA identifier of "Europe/Lisbon". You can find a list of identifiers here. Picking the correct identifier is important, as time zones change over time. Each identifier reflects the particular history of each region.
One you know the IANA time zone identifier, then you have options for how to use it:
In some modern browsers that fully support the time zone features of the ECMAScript Internationalization API (ECMA-402), you can do the following:
var d = new Date();
var s = d.toLocaleString(undefined, { timeZone: "Europe/Lisbon" })
This will convert the provided date and time to the correct time zone during formatting. Passing undefined in the first parameter will use the current locale for formatting.
There are a few downsides to this approach, as it is not yet implemented in all browsers, and there is no API for just retrieving the raw time zone offset of a particular point in time.
You can consider using a library that implements this functionality. I list several of them here. My personal preference is for moment.js with the moment-timezone addon, which you can do the following:
var m = moment.tz("Europe/Lisbon");
var s = m.format();
You can pass parameters to the format method to display the output however you like. You can also convert an existing time, such as:
var m = moment.utc("2016-01-01T00:00:00").tz("Europe/Lisbon");
var s = m.format();
You can also get the offset for a particular moment in time like so:
var m = moment.utc("2016-01-01T00:00:00").tz("Europe/Lisbon");
var offsetInMinutes = m.utcOffset();
var offsetAsString = m.format("Z");
You can write your own code for handling a particular time zone. Though this can be error prone and I don't generally recommend it. Updates can be particularly difficult if you go down this route.
Do also keep in mind that the offset for a particular time zone will vary depending on the date and time in effect. Therefore, new Date() which represents "now" may or may not always be the correct input, depending on your scenario.
I wanted to without a library too, but even with moment it has a fixed amount of timezone data so will break after 30 years if you don't keep updating, just erks me a bit. although this does use strings, nothing more complicated than parsing a string which is just an number
function getTimezoneOffset(dt, timezone) {
let getItem = function(format) {
format.timeZone = timezone;
return parseInt(dt.toLocaleString(
'en-US', format));
};
let adjDate = new Date(
getItem({year: 'numeric'}),
getItem({month: 'numeric'}) - 1, // months are zero based
getItem({day: 'numeric'}),
getItem({hour: 'numeric',hour12: false}),
getItem({minute: 'numeric'}));
let noSecs = new Date(dt.getTime());
noSecs.setSeconds(0, 0);
let diff = Math.round((adjDate.getTime() - noSecs.getTime()) / 60000);
return dt.getTimezoneOffset() - diff;
}
I wanted to do this without using a library, so I wrote this function that gives you the timezone offset between the given timezone and utc:
function getTimezoneOffsetFrom(otherTimezone) {
if (otherTimezone === void 0) { otherTimezone = "Europe/Amsterdam"; }
var date = new Date();
function objFromStr(str) {
var array = str.replace(":", " ").split(" ");
return {
day: parseInt(array[0]),
hour: parseInt(array[1]),
minute: parseInt(array[2])
};
}
var str = date.toLocaleString(['nl-NL'], { timeZone: otherTimezone, day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: false });
var other = objFromStr(str);
str = date.toLocaleString(['nl-NL'], { day: 'numeric', hour: 'numeric', minute: 'numeric', hour12: false });
var myLocale = objFromStr(str);
var amsterdamOffset = (other.day * 24 * 60) + (other.hour * 60) + (other.minute);
var myLocaleOffset = (myLocale.day * 24 * 60) + (myLocale.hour * 60) + (myLocale.minute);
return myLocaleOffset - amsterdamOffset + date.getTimezoneOffset();
}
Maybe it can be approved by using en-US as a locale string and then the str.replace maybe needs to filter a comma or something.
function getTimezoneOffset(atTime, timeZone) {
const localizedTime = new Date(atTime.toLocaleString("en-US", {timeZone}));
const utcTime = new Date(atTime.toLocaleString("en-US", {timeZone: "UTC"}));
return (localizedTime.getTime() - utcTime.getTime()) / (60*60*1000);
}
// returns -6 or -7 depending on the time of year
console.log(getTimezoneOffset(new Date(), "America/Denver"));
// returns -5 or -6 depending on the time of year
console.log(getTimezoneOffset(new Date(), "America/Chicago"));

Locale specific date without year

I am using https://github.com/abritinthebay/datejs/ for date formatting due to locale support. However, is it not possible to get a full date time without year?
Example
Input date:2014/09/20 20:00:00
Output date: 09/20 20:00
And it has to respect locale settings!
Looks like since ES2015 you can just skip first parameter and set only 'options' parameter, in that way locale will be applied:
new Date().toLocaleString(undefined, {
month: "short", day: "numeric",
hour: "numeric", minute: "numeric", second: "numeric"
}) // "Jul 11, 5:50:09 PM"
I didn't find the way to remove comma between date and time. For that case string formatting can be used:
const dateTime = new Date();
const datePart = dateTime.toLocaleDateString(undefined, {month: "short", day: "numeric"});
const timePart = dateTime.toLocaleTimeString();
const result = `${datePart} ${timePart}`;
// "Jul 11 5:57:10 PM"
console.log(new Date().toLocaleString('en-En',{weekday: "long", month: "long", day: "numeric"}))
You can change this options as you want.
To format a date as month/day hour:minute with Date.js you'd call toString with the format 'MM/DD HH:mm' to get two digits for all values, e.g.:
console.log(new Date().toString('MM/dd HH:mm'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/datejs/1.0/date.min.js"></script>
Attempting to determine the format that the user expects to see is very problematic, whether it's referred to as "culture", "locale" or just "preference". Javascript doesn't have access to system settings and the browser doesn't reveal them. You can try to guess based on the output of Date.prototype.toLocaleString, but that is entirely implementation dependent and doesn't necessarily conform to user preferences.
One common approach is to use an unambiguous format so user preferences don't matter, e.g.
console.log(new Date().toString('dd-MMM HH:mm'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/datejs/1.0/date.min.js"></script>
Another approach is to have an unambiguous default format, then allow the user to select from a few supported formats and store the preference.
There is also the built–in Date.prototype.toLocaleString, which is pretty unreliable but some browsers support the optional ECMA-402 Intl formatting options. It's pretty ordinary as a formatter so really can't be recommended when there are libraries that do the job so much better, e.g.
var options = {
month: 'short',
day : '2-digit',
hour : '2-digit',
minute:'2-digit'
};
// Browser dependent, something like en-us: Jan 21, 8:39 AM
console.log('en-us: ' + new Date().toLocaleString('en-us',options))
// Browser dependent, something like en-gb: 21 Jan, 08:39
console.log('en-gb: ' + new Date().toLocaleString('en-gb',options))
Yet another approach is to write your own parser and formatter that does just what you need. If you only need to support one or two formats, it's pretty straight forward, e.g.
// input format yyyy/mm/dd hh:mm:ss
function parseDateString(ds) {
var d = ds.split(/\D+/);
return new Date(d[0], --d[1], d[2], d[3], d[4], d[5]);
}
// Return date string as mm/dd hh:mm
function formatDate(d) {
function z(n) {
return (n < 10 ? '0' : '') + n
}
return z(d.getMonth() + 1) + '/' + z(d.getDate()) +
' ' + z(d.getHours()) + ':' + z(d.getMinutes());
}
console.log(formatDate(parseDateString('2014/09/20 20:00:00'))); // 09/20 20:00
So you can replace an entire library with less than a dozen lines of code. :-)

Categories

Resources