Calculate datetime correctly in UTC from date string - javascript

I'm trying to calculate the datetime in UTC, i have the bellow code and using Luxon
weeklyDish.orderBeforeTime = timeZoneToUTC(
"Europe/Amsterdam",
year,
month,
day,
hours
);
function timeZoneToUTC(timezone, year, month, day, hours) {
const dateObj = `${year}-${month}-${day} ${hours}:00`;
const datetime = DateTime.fromFormat(dateObj, "yyyy-M-d H:mm", {
zone: timezone,
});
return datetime.toUTC().toString();
}
The code above always return the wrong hour.
How can I get the year, month, hour and return a UTC string to save in the DB?
I'm going to be migrating data that has date as string (example: "2020-12-13"), how can I convert it to UTC date and subtract days correctly?

You need to show an example to demonstrate your issue. The following shows use of Luxon's UTC and setZone methods that both seem to correctly convert a date set for "Europe/Amsterdam".
Note that the string passed to DateTime.fromISO must form a valid ISO 8601 timestamp like YYYY-MM-DDTHH.
let DateTime = luxon.DateTime;
let [tz, y, m, d, h] = ["Europe/Amsterdam", '2020', '11', '30', '12'];
let date = DateTime.fromISO(`${y}-${m}-${d}T${h}`, { zone: "Europe/Amsterdam" });
console.log(tz + '\n' + date.toString());
let dateUTC = date.setZone('UTC');
console.log('setZone to UTC\n' + dateUTC.toString());
let dateUTC2 = date.toUTC();
console.log('toUTC method\n' + dateUTC2.toString());
<script src="https://cdn.jsdelivr.net/npm/luxon#1.25.0/build/global/luxon.min.js"></script>
PS Amsterdam standard time is +1, daylight saving time is +2.

If the date is already parsed, you can use the date constructor directly. However, the constructor depends on the local timezone, luckily you can use Date.UTC instead.
The tricky part is about the timezone, which is not supported in the constructor, but it's a simple addition anyway.
So I'd wager something like so should work:
function timeZoneToUTC(timezone, year, month, day, hours) {
return new Date(Date.UTC(year, month - 1, day, hours + timezone));
}
Note: the month parameter is an index (0-based), so if you have 1=January, you need to decrease your month by one (as in my example).
Edit: uh, apparently, Date.UTC returns a timestamp, so you need to use the constructor anyway.

Related

Comparing two PST DateTime objects

I am trying to convert a given date to PST timezone and compare it with a given date time. I am getting the current time in PST using the following method:
var today = new Date().toLocaleString("en-US", {
timeZone: "America/Los_Angeles"
})
The output is of the following format:
3/16/2022, 12:27:28 AM
Now, I am creating a date time object to compare with the above date time:
var cmpdate = new Date("2022-03-16 23:59:59").toLocaleString("en-US")
Output is the following:
3/16/2022, 11:59:59 PM
I wanted the comparing date time object to be the last moment of the given date. That's why passing 23:59:59.
Now, when I compare these two, I am not getting the output properly because toLocaleString() is converting the dates to string and the comparison is happening as string comparison.
if(today <= cmpdate)
console.log("yes")
else
console.log("no")
For the given above input, it is printing no always but ideally it should be printing yes. The issue is because of the 12:27:28 present in first time object, I guess. Then I don't know how to resolve this without using any third party libraries.
Any hints on how to implement this PST comparison?
I'd suggest using a dedicated library for this purpose, luxon for example will make this very straightforward.
We can use the .fromFormat() function to parse the cmpdate value, while setting the correct zone.
Getting current time just means a call to DateTime.now(), then calling .setZone().
Once we have created our values, we can simply use the <, >, <=, and >= operators to compare them. See comparing-datetimes.
Rather then setting the cmpdate value to 2022-03-16 23:59:59 and using <=, I'd suggest setting it to 2022-03-17 00:00:00 and using the < operator. This simplifies the logic:
const { DateTime } = luxon;
const zone = 'America/Los_Angeles';
let cmpdate = DateTime.fromFormat('2022-03-17 00:00:00', 'yyyy-MM-dd HH:mm:ss', { zone });
let today = DateTime.now().setZone(zone);
console.log(`cmpdate (${zone}): `, cmpdate.toFormat('yyyy-MM-dd HH:mm:ss'));
console.log(`today (${zone}): `, today.toFormat('yyyy-MM-dd HH:mm:ss'));
console.log('today < cmpdate: ', today < cmpdate);
// Skipping the conversion of now() to LA time will also work, since the timestamps are converted to epoch timestamps before comparing
console.log('now() < cmpdate: ', DateTime.now() < cmpdate);
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/2.3.1/luxon.min.js" integrity="sha512-Nw0Abk+Ywwk5FzYTxtB70/xJRiCI0S2ORbXI3VBlFpKJ44LM6cW2WxIIolyKEOxOuMI90GIfXdlZRJepu7cczA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
You can do this with native JS Date values, by getting the time in the relevant timezone, as an ISO string, then comparing.
By passing the locale 'sv' to the .toLocaleString() call, we convert the date to an ISO string.
Since ISO date strings are sortable, we can compare using the < > etc operators.
const timeZone = 'America/Los_Angeles';
const now = new Date();
const cmpdate = '2022-03-17 00:00:00';
let today = now.toLocaleString('sv', { timeZone });
let tomorrow = new Date(now.getTime());
tomorrow.setDate(now.getDate() + 1);
tomorrow = tomorrow.toLocaleString('sv', { timeZone });
console.log('cmpdate (LA Time): ', cmpdate);
console.log('today (LA Time): ', today);
console.log('tomorrow (LA Time):', tomorrow);
console.log('today < cmpdate: ', today < cmpdate);
console.log('tomorrow < cmpdate:', tomorrow < cmpdate);

How to use the Time period in date time

I have a form that sends the value of year and months from an input and then while sending the value to the server I am converting that values to ISO string like that:
const toIsoString = (year, month, day) => moment(new Date(year, month - 1, day)).toISOString(true).split('.')[0];
And then in the values I am using it like this.
StartDate: toIsoString(data.StartYear, parseInt(data.StartMonth, 10), 1),
In that case It is sending the value like this:
startDate: "2021-01-01T00:00:00"
Does anybody know why the Time period is being ignored and how can I also send the time period with the year, month and date values.Any helps would be highly appreciated.Thanks...
Does anybody know why the Time period is being ignored and how can I also send the time period with the year, month and date values.Any helps would be highly appreciated.
The time isn't ignored. In the function:
const toIsoString = (year, month, day) =>
moment(new Date(year, month - 1, day)).toISOString(true).split('.')[0];
the values for hour, minute, second and millisecond are omitted so they default to 0. What time are you expecting?
If you want the current local time added to the date, then create a date and set the year, month and day to the required values without modifying the time (though I don't know why you'd want to do that).
Rather than creating a string that you then need to further process, tell moment.js the format you want:
function toIsoString (year, month, day) {
return moment(new Date().setFullYear(year, month-1, day)).format('YYYY-MM-DD HH:mm:ss');
}
console.log(toIsoString('2021','1','1'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.26.0/moment.min.js"></script>
You can also do that without a library, see How to format a JavaScript date, e.g.:
function formatDate(year, month, date) {
let z = n => (n<10?'0':'') + Number(n);
return `${year}-${z(month)}-${z(date)} ${
new Date().toLocaleString('en',{
hour12:false,
hour:'2-digit',
minute:'2-digit',
second:'2-digit'})
}`;
}
console.log(formatDate('2021','1','01'))
Its because you are only setting year, month and date while creating moment object. You are not setting time
You should do something like
const toIsoString = (year, month, day) => {
const currDate = moment(new Date());
currDate.year(year);
currDate.month(month - 1);
currDate.date(day);
return currDate.toISOString(true).split('.')[0];
}
Or simply use set function
const toIsoString = (year, month, day) => {
const currDate = moment(new Date());
currDate.set({
'year': year,
'month': (month - 1),
'date': day
});
return currDate.toISOString(true).split('.')[0];
}

Javascript get UTC out of date and time variables

I have two variables in javascript like:
time: 02:00
date: 25-08-2017
and I'm wondering if I can put these into a Date() object and get the UTC date and time out of it in hours/minutes using getUTCDay(), getUTCHours() and getUTCMinutes() and place them back in the format I got them.
I can load moment.js for it but if I don't have to it would be nice if I can do it without.
Convert your strings to an ISO 8601 string and use it in the Date constructor. From there, you can get whatever data you need
let time = '02:00'
let date = '25-08-2017'
let iso8601Date = date.split('-').reverse().join('-')
let dt = new Date(`${iso8601Date}T${time}`) // will be interpreted as local time
const digitFormatter = new Intl.NumberFormat(undefined, {minimumIntegerDigits: 2})
console.info('Parsed date:', dt)
console.info('UTC date in dd-mm-yyyy:',
`${digitFormatter.format(dt.getUTCDate())}-${(digitFormatter.format(dt.getUTCMonth() + 1))}-${dt.getUTCFullYear()}`
)
console.info('UTC time:', `${digitFormatter.format(dt.getUTCHours())}:${digitFormatter.format(dt.getUTCMinutes())}`)

from unix timestamp to datetime

I have something like /Date(1370001284000+0200)/ as timestamp. I guess it is a unix date, isn't it? How can I convert this to a date like this: 31.05.2013 13:54:44
I tried THIS converter for 1370001284 and it gives the right date. So it is in seconds.
But I still get the wrong date for:
var substring = unix_timestamp.replace("/Date(", "");
substring = substring.replace("000+0200)/", "");
var date = new Date();
date.setSeconds(substring);
return date;
Note my use of t.format comes from using Moment.js, it is not part of JavaScript's standard Date prototype.
A Unix timestamp is the number of seconds since 1970-01-01 00:00:00 UTC.
The presence of the +0200 means the numeric string is not a Unix timestamp as it contains timezone adjustment information. You need to handle that separately.
If your timestamp string is in milliseconds, then you can use the milliseconds constructor and Moment.js to format the date into a string:
var t = new Date( 1370001284000 );
var formatted = moment(t).format("dd.mm.yyyy hh:MM:ss");
If your timestamp string is in seconds, then use setSeconds:
var t = new Date();
t.setSeconds( 1370001284 );
var formatted = moment(t).format("dd.mm.yyyy hh:MM:ss");
Looks like you might want the ISO format so that you can retain the timezone.
var dateTime = new Date(1370001284000);
dateTime.toISOString(); // Returns "2013-05-31T11:54:44.000Z"
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
Without moment.js:
var time_to_show = 1509968436; // unix timestamp in seconds
var t = new Date(time_to_show * 1000);
var formatted = ('0' + t.getHours()).slice(-2) + ':' + ('0' + t.getMinutes()).slice(-2);
document.write(formatted);
The /Date(ms + timezone)/ is a ASP.NET syntax for JSON dates. You might want to use a library like momentjs for parsing such dates. It would come in handy if you need to manipulate or print the dates any time later.
If using react:
import Moment from 'react-moment';
Moment.globalFormat = 'D MMM YYYY';
then:
<td><Moment unix>{1370001284}</Moment></td>
Import moment js:
var fulldate = new Date(1370001284000);
var converted_date = moment(fulldate).format(");
if you're using React I found 'react-moment' library more easy to handle for Front-End related tasks, just import <Moment> component and add unix prop:
import Moment from 'react-moment'
// get date variable
const {date} = this.props
<Moment unix>{date}</Moment>
I would like to add that Using the library momentjs in javascript you can have the whole data information in an object with:
const today = moment(1557697070824.94).toObject();
You should obtain an object with this properties:
today: {
date: 15,
hours: 2,
milliseconds: 207,
minutes: 31,
months: 4
seconds: 22,
years: 2019
}
It is very useful when you have to calculate dates.
for people as dumb as myself, my date was in linux epoch
but it was a string instead of an integer, and that's why i was getting
RangeError: Date value out of bounds
so if you are getting the epoch from an api, parseInt it first
var dateTime = new Date(parseInt(1370001284000));
dateTime.toISOString();

Javascript to compare two dates, from strings, begin <= end

I get two strings formated like (Brazilian Format): "DD/MM/YYYY", I need to compare both. Since the first field is the begin and the last is the end,
My validation is begin <= end
Date.new(begin) is generating 'invalid date' even on ISO !
Don't use Date.new. Use new Date(). Because of the format of your date string, I would recommend grabbing each field individually and passing them into the constructor:
var startYear = parseInt(document.getElementById('startYear'), 10);
var startMonth = parseInt(document.getElementById('startMonth'), 10) - 1; // as per Residuum's comment
var startDay = parseInt(document.getElementById('startDay'), 10);
var start = new Date(startYear, startMonth, startDay);
etc. If you're handed a date string, then you can use fuzzy lollipop's method to get each field from the string. I'm not sure if the Date constructor will accept unparsed strings for the individual fields, however.
The, once you have the two dates you'd like to compare, just compare their values in milliseconds since the epoch:
function isValid(start, end) {
return start.getTime() < end.getTime();
}
There's a nice date handling library called datejs which has a parseExact(dateStr, format) method.
you can do this, if you know your date will always be formatted the same way dd/mm/yyyy
today = "23/02/1001";
dateComponents = today.split("/");
date = new Date(dateComponents[2], dateComponents[1] - 1, dateComponents[0]);
but a better solutions is to look at this page there is Datejs which is a good alternative to date processing.
Quick 'n dirty :
function is_valid (start , end) {
return start.split('/').reverse().join('') <= end.split('/').reverse().join('') ;
}
That is, split the date into components, reverse the order join them again and do a string comparison.
Edit: As noted in the comment, of course this won't work if your month/days smaller than 10 are not zero padded.
The new 'hotness' in JS time world: http://momentjs.com/
Fits this use-case as well
Here are all available constructors for date objects in Javascript:
dateobject = new Date(); // returns date of current time stamp
// on the browser
dateobject = new Date("Month Day, Year Hours:Minutes:Seconds");
dateobject = new Date(Year, Month, Day);
dateobject = new Date(Year, Month, Day, Hours, Minutes, Seconds);
dateobject = new Date(Milliseconds);
Pick the one you try to use, but I would go for new Date(Year, Month, Day); in your case.
EDIT:
Note: Monthis zero-based in Javascript, so January 1 2010, will be new Date(2010, 0, 1) and December 31 2011 is new Date(2010, 11, 31).

Categories