I have two values. one a [STRING] and one an [INT]
TimeZone is a string of one of these values:
'EST-5:00' || 'CST-6:00' || 'MST-7:00' || 'PST-8:00'
DST will be an INT of 0 || 1.
Trying to figure out how best to get offset.
offset = MATH.abs(TimeZone# + DST) ie.
let offset = MATH.abs(-5 + 1) // = 4 ('EST-5:00') + (DST = 1)
or
let offset = MATH.abs(-6 + 0) // = 6 ('CST-6:00') + (DST = 0)
or
let offset = MATH.abs(-8 + 1) // = 7 ('PST-8:00') + (DST = 1)
What is the best way to parse the string to get the number value and add the value of DST?
My end goal is actually to get a DateTime I have such as:
let DateTime = '2017-05-11 10:34:43'
along with the TimeZone String above (retrieved from metadata related to the event) and transform it to UTC using the DST Int (retrieved from metadata related to the event) ...
So I am trying to find out how much I need to add (hours) to the DateTime to set it to UTC given the data I have to work with.
so
let utcTime = moment(DateTime).add(offset, 'h');
You could do a regular expression with a match group on the digit:
var value = '(\'PST-8:00\')'.match(/\w{3}-(\d{1})\:/).pop() + DST // => 8 + DST
It looks for a series of 3 word characters, followed by a hyphen, and then matches on a single digit, before ending at a colon character.
This was just a quick on off the top of my head, so I'm sure there are ways to tighten up the regex, but the principle is still the same (see the String.prototype.match docs on MDN).
You only want the number part, so you can use a regular expression to get the hour and minute values:
var tz = 'EST-5:00';
var hm = tz.match(/[+-]?\d\d?/g);
will get the time parts. hm[0] is the hour part with sign and `hm[1] is the minute part. If you want the letter part as well, that can be accommodated too:
var hm = tz.match(/[a-z]+|[+-]?\d\d?/ig);
Some timezones go down to 15 minutes and daylight offsets can be 30 minutes, so it's more compatible to express the offset in minutes than hours (though it should be in ±hh:mm format for humans). You should also keep the minutes part and the sign:
var tz = 'EST-5:00';
function offsetToMins(s) {
var hm = s.match(/[+-]?\d\d?/g) || []; // Avoid null
var h = hm[0] * 60;
var m = +hm[1];
// A bit of validation
if (isNaN(h) || isNaN(m)) {
return 'Invalid input: ' + '"' + s + '"';
}
return h + (h<0? m*-1 : m);
}
console.log(offsetToMins(tz)) // -300
console.log(offsetToMins('IST+05:30')) // 330
console.log(offsetToMins('foo')) // Invalid input: "foo"
Now the daylight saving offset can be added in minutes and the value can be presented in a suitable human readable format, e.g. -06:00, -6:00, -0600, whatever.
Related
While working on multiple timezones, I have a case where I create shifts in multiple timezones, now users apply for those shifts.
It's highly time-sensitive. Now what I want to take input of which timezone the shift is in (example Australia/Sydney)
Solution : Now while before saving it into the database I am converting the timezone to UTCoffset meaning in example Australia/Sydney timezone I am setting offset with - example Australia offset is 600 then -600 setting the offer and storing into the db.
const getUTCOffset = timezone => Intl.DateTimeFormat([], {timeZone: timezone, timeZoneName: 'shortOffset'}).formatToParts().find(o => o.type === 'timeZoneName').value.match(/\-?\d+/)[0]*60;
(getUTCOffset('Australia/Sydney'))
Is there anything I am missing here? What could be the optimal solution for this?
I think what you're missing is that offsets change from time to time due to historic changes and daylight saving. You are much better off to store the IANA location and calculate the offset as required.
If you want to get the offset for a location in minutes (which is convenient) then consider:
function getOffsetInMinutes(loc, date = new Date()) {
let [year, sign, hr, min] = date.toLocaleString('en', {
year:'numeric',
timeZone:loc,
timeZoneName:'longOffset'
}).match(/\d+|\+|\-/g);
return (sign == '+'? 1 : -1) * (hr*60 + min*1);
}
['Asia/Kolkata',
'Australia/Sydney',
'America/New_York'
].forEach(
loc => console.log(loc + ': ' + getOffsetInMinutes(loc))
);
For browsers that don't support the newer timeZoneName option values (like Safari ), you can use a function that uses the value "short" instead. The following returns the offset as ±HH:mm, it's not hard to modify to return minutes as above.
// Return offset on date for loc in ±HH:mm format
function getTimezoneOffset(loc, date=new Date()) {
// Try English to get offset. If get abbreviation, use French
let offset;
['en','fr'].some(lang => {
// Get parts - can't get just timeZoneName, must get one other part at least
let parts = new Intl.DateTimeFormat(lang, {
minute: 'numeric',
timeZone: loc,
timeZoneName:'short'
}).formatToParts(date);
// Get offset from parts
let tzName = parts.filter(part => part.type == 'timeZoneName' && part.value);
// timeZoneName starting with GMT or UTC is offset - keep and stop looping
// Otherwise it's an abbreviation, keep looping
if (/^(GMT|UTC)/.test(tzName[0].value)) {
offset = tzName[0].value.replace(/GMT|UTC/,'') || '+0';
return true;
}
});
// Format offset as ±HH:mm
// Normalise minus sign as ASCII minus (charCode 45)
let sign = offset[0] == '\x2b'? '\x2b' : '\x2d';
let [h, m] = offset.substring(1).split(':');
return sign + h.padStart(2, '0') + ':' + (m || '00');
}
['Asia/Kolkata','Australia/Sydney','America/New_York'].forEach(
loc => console.log(loc + ': ' + getTimezoneOffset(loc))
);
I have date with format '2021-05-01T23:59:59.999-05:00'
Need to fetch utc offset value like 300, 330 etc.
Can someone help here.Any Answer without using moment.js is appreciated.
So extracting value -05:00 from '2021-05-01T23:59:59.999-05:00'
The function Date.getTimezoneOffset() will only ever give you the offset between the client machine timezone and UTC, it won't give you the UTC offset as specified in the ISO date string.
Given that the dates are in ISO-8601 format, we can parse the UTC offset from the data, it will be in the format ±[hh]:[mm], ±[hh][mm], ±[hh] or 'Z' for UTC / Zulu time.
Negative UTC offsets describe a time zone west of UTC±00:00, where the civil time is behind (or earlier) than UTC so the zone designator will look like "−03:00","−0300", or "−03".
Positive UTC offsets describe a time zone at or east of UTC±00:00, where the civil time is the same as or ahead (or later) than UTC so the zone designator will look like "+02:00","+0200", or "+02".
We'll use regular expressions to parse the timezone offsets, this will work on IE 11 too.
function getUTCOffsetMinutes(isoDate) {
// The pattern will be ±[hh]:[mm], ±[hh][mm], or ±[hh], or 'Z'
const offsetPattern = /([+-]\d{2}|Z):?(\d{2})?\s*$/;
if (!offsetPattern.test(isoDate)) {
throw new Error("Cannot parse UTC offset.")
}
const result = offsetPattern.exec(isoDate);
return (+result[1] || 0) * 60 + (+result[2] || 0);
}
const inputs = [
'2021-05-01T23:59:59.999+12:00',
'2021-05-01T23:59:59.999+10',
'2021-05-01T23:59:59.999+0530',
'2021-05-01T23:59:59.999+0300',
'2021-05-01T23:59:59.999Z',
'2021-05-01T23:59:59.999-05:00',
'2021-05-01T23:59:59.999-07:00',
];
for(var i = 0; i < inputs.length; i++) {
console.log('input:', inputs[i], 'offsetMinutes:', getUTCOffsetMinutes(inputs[i]));
}
Pretty much the same as #TerryLennox but deals with:
Seconds in the offset—fairly common before 1900, added as decimal part of minutes
Missing offset—local, returns undefined
function parseOffset(ts) {
let [all,hr,min,sec] = (''+ts).match(/([+-]\d{2}|Z):?(\d{2})?:?(\d{2})?$/) || [];
let sign = hr < 0 ? -1 : 1;
return !all ? all : // No match, return undefined
hr == 'Z' ? 0 :
hr * 60 + (min? sign * min : 0) + (sec? sign * sec / 60 : 0);
}
['2021-05-01T23:59:59.999-05:30',
'2021-05-01T23:59:59.999+05:30',
'2021-05-01T23:59:59.999-0530',
'2021-05-01T23:59:59.999+0530',
'2021-05-01T23:59:59.999-05',
'2021-05-01T23:59:59.999+05',
'2021-05-01T23:59:59.999+053012',
'2021-05-01T23:59:59.999+05:30:12',
'2021-05-01T23:59:59.999Z',
'2021-05-01T23:59:59.999',
'blah'
].forEach(ts => console.log(ts + ' -> ' + parseOffset(ts)));
I was referring this link and as I do not have 50 reputation I am not allowed to comment in the answer so posting this question. I did not get the statement where you can see a month is subtracted from months. This can be simple one but could anyone please clarify on this?
var m = matches1 - 1; ?
function isValidDate(date)
{
var matches = /^(\d{2})[-\/](\d{2})[-\/](\d{4})$/.exec(date);
if (matches == null) return false;
var d = matches[2];
var m = matches[1] - 1;
var y = matches[3];
var composedDate = new Date(y, m, d);
return composedDate.getDate() == d &&
composedDate.getMonth() == m &&
composedDate.getFullYear() == y;
}
var m = matches1 - 1; ?
months index starts from 0.
So while you think Jan is 1, it is actually 0 when you do date.getMonth().
Which is why when you get 1 from a date-string, you need to make it 0 before setting it to a date object.
In the spirt of the question, the validation function is way overdone. Only the month needs to be checked since if either the day or month is out of bounds, the month of the generated date will change.
Also the regular expression can be greatly simplified, consider (assuming the input is the peculiar US m/d/y format):
/* Validate a date string in US m/d/y format
** #param {string} s - string to parse
** separator can be any non–digit character (.-/ are common)
** leading zeros on values are optional
** #returns {boolean} true if string is a valid date, false otherwise
*/
function validateMDY(s) {
var b = s.split(/\D/);
var d = new Date(b[2],--b[0],b[1]);
return b[0] == d.getMonth();
}
var testData = ['2/29/2016', // Valid - leap year
'2/29/2015', // Invalid - day out of range
'13/4/2016', // Invalid - month out of range
'13/40/2016', // Invalid - month and day out of range
'02/02/2017']; // Valid
document.write(testData.map(function(a) {
return a + ': ' + validateMDY(a);
}).join('<br>'));
I'm working on a web timesheet where users use timepicker to determine start & end times and I'd like to have the form automatically find the difference between the two times and place it in a 3rd input box. I understand that I need to get the values, convert them to milliseconds, then subtract the first number from the second, convert the difference back to human time and display that in the third box. But I can't seem to wrap my head around time conversion in javascript. Here's what I have so far:
function date1math(){
var date1in = document.getElementById("date-1-in").value;
var date1out = document.getElementById("date-1-out").value;
date1in = date1in.split(":");
date1out = date1out.split(":");
var date1inDate = new Date(0, 0, 0, date1in[0], date1in[1], 0);
var date1outDate = new Date(0, 0, 0, date1out[0], date1out[1], 0);
var date1math = date1outDate.getTime() - date1inDate.getTime();
var hours = Math.floor(date1math / 1000 / 60 / 60);
date1math -= hours * 1000 * 60 * 60;
var minutes = Math.floor(date1math / 1000 / 60);
return (hours < 9 ? "0" : "") + hours + ":" + (minutes < 9 ? "0" : "") + minutes;
document.getElementById("date-1-subtotal").value = date1math(date1in, date1out);
}
I want to take the timepicker result (say 9:00am) from the input date-1-in, the timepicker result (say 5:00pm) from the input date-1-out, and then place the difference as a number in date-1-subtotal.
Presumably the input is a string in the format hh:mm (e.g. 09:54) and that the two strings represent a time on the same day. You don't mention whether an am/pm suffix is included, but it's there in the text so I'll assume it might be.
If daylight saving changes can be ignored, the simplest method is to convert the string to minutes, find the difference, then convert back to hours and minutes, e.g.:
// Convert hh:mm[am/pm] to minutes
function timeStringToMins(s) {
s = s.split(':');
s[0] = /m$/i.test(s[1]) && s[0] == 12? 0 : s[0];
return s[0]*60 + parseInt(s[1]) + (/pm$/i.test(s[1])? 720 : 0);
}
// Return difference between two times in hh:mm[am/pm] format as hh:mm
function getTimeDifference(t0, t1) {
// Small helper function to padd single digits
function z(n){return (n<10?'0':'') + n;}
// Get difference in minutes
var diff = timeStringToMins(t1) - timeStringToMins(t0);
// Format difference as hh:mm and return
return z(diff/60 | 0) + ':' + z(diff % 60);
}
var t0 = '09:15am';
var t1 = '05:00pm';
console.log(getTimeDifference('09:15am', '05:00pm')); // 07:45
console.log(getTimeDifference('09:15', '17:00')); // 07:45
If daylight saving is to be incorporated, you'll need to include the date so that date objects can be created and used for the time difference. The above can use either 12 or 24 hr time format.
I'm interfacing with an api and they use .NET so all of my time stamps need to conform to .NET's Date Time format which looks something like this
/Date(1379142000000-0700)/
I would like to convert unix times to this format using javascript. I've seen this function for moment.js but this dosn't return the unix/epoch formatting and it's in the wrong direction.
How can I convert unix timestamp to .net time formatting with javascript?
solutions using moment.js are good, and bonus points for converting from .net to unix as well.
If you have a date object, it seems like you need the UTC millisecond time value and the timezone offset in hours and minutes (hhmm). So presuming that the UNIX time value is UTC and that the ".NET" time string is a local time value with offset, then:
function unixTimeToDotNetString(v) {
// Simple fn to add leading zero to single digit numbers
function z(n) {
return (n < 10 ? '0' : '') + n;
}
// Use UNIX UTC value to create a date object with local offset
var d = new Date(v * 1e3);
// Get the local offset (mins to add to local time to get UTC)
var offset = d.getTimezoneOffset();
// Calculate local time value by adding offset
var timeValue = +d + offset * 6e4;
// Get offset sign - reverse sense
var sign = offset < 0 ? '+' : '-';
// Build offset string as hhmm
offset = Math.abs(offset);
var hhmm = sign + z(offset / 60 | 0);
hhmm += z(offset % 60);
// Combine with time value
return timeValue + hhmm;
}
var unixTime = 1393552984;
console.log(unixTime + ' : ' + unixTimeToDotNetString(unixTime)); // 1393552984 : 1393517104000+1000
The difference between the two time values shoudl be equivalent to the offset in milliseconds (in this case where the timezone is UTC+1000 it's 36000000).