How to get difference between dates in different timezones using moment? - javascript

I'm using momentJS to get difference between 2 dates. Here is my code:
const createdAt = "2019-11-15 09:45:21"; // Sample data from mysql database
// Add time since created
const created = moment(createdAt);
const now = moment();
// get the difference between the moments
const diff = now.diff(created);
//express as a duration
const diffDuration = moment.duration(diff);
const days = diffDuration.days().toString().padStart(2, 0);
const hours = diffDuration.hours().toString().padStart(2, 0);
const minutes = diffDuration.minutes().toString().padStart(2, 0);
With that code, I can properly get the days, hours and minutes difference. The server where mysql is installed is in the Philippines and the createdAt value is automatically generated by mysql.
Now when I try to change my PC's timezone, I get incorrect date difference. I get negative values.
I tried doing something like adding utc():
const created = moment.utc(createdAt);
const now = moment.utc();
And I still don't get any correct values. Am I missing something? Is it possible to do this? Thanks in advance.

The createdAt time above is not UTC format so you will need to update the value by adding/subtracting the hours from your local time, or utc time. It's best to convert the relevant dates to UTC and then perform your diff from there.
Take a look at the options below for parsing and values:
// utc time now
const utcTime = moment.utc();
console.log(utcTime.toString());
// time recorded at server
const philliTime = moment('2019-11-15 09:45:21', 'YYYY-MM-DD HH:mm:ss');
console.log(philliTime.toString());
// need to add 8 hours as philli is +8 hours
philliTime.add(8, 'h');
console.log(philliTime.toString());
// options using parseZone
const optionBPhilli = moment.parseZone('2019-11-15 09:45:21 +08:00', 'YYYY-MM-DD HH:mm:ss ZZ');
console.log(optionBPhilli.toString());
const optionBUTC = moment.parseZone('2019-11-15 09:45:21 +00:00', 'YYYY-MM-DD HH:mm:ss ZZ');
console.log(optionBUTC.toString());
console.log(optionBPhilli.diff(optionBUTC, 'h'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
For more info on parsing the string, check the moment docs and also look at UTC parsing.

Related

JavaScript Date time different once deployed to Heroku

Locally, everything is accurate by the minute. Once deployed to Heroku, the difference between the times are off by about 6 hours. I am not looking to convert Heroku time zone (would like it to remain UTC). I've tried everything from getTimezoneOffset() conversions to different date formats and I still end up with the same result. How can I have these 2 date times match each other and not be offset by hours when deployed? Why are they different, when formatted the exact same way?
// Used to calculate current date time
const currentDate = new Date();
// ^ Production - (2021-10-12T19:12:41.081Z)
const time = `${currentDate.getHours()}:${currentDate.getMinutes()}`;
const fullDate = `${currentDate.getMonth()}/${currentDate.getDate()}/${currentDate.getFullYear()}`;
const currentDateFormatted = new Date(`${fullDate} ${time}`);
// ^ Production - (2021-10-12T19:12:00.000Z)
const currentParsedDateToUTC = Date.parse(currentDateFormatted.toUTCString());
// Used to calculate an event date time
const eventDate = new Date(`${event.date} ${event.endTime}`); // same exact format as above
// ^ Production - (2021-10-12T13:12:00.000Z)
const eventParsedDateToUTC = Date.parse(eventDate.toUTCString());
const isExpired = (currentParsedDateToUTC > eventParsedDateToUTC); // works locally, but not in production
In this example, the event date and start time is identical to the current date time. How can I prevent them from being vastly different?
That is because the Heroku server is in a different timezone than yours, you can handle it by converting the time format from your frontend, I recommend you use moment.js for example in your frontend you can convert like this:
npm install moment --save
And then you can create a function just to change the format to display:
const formatDatetime = (
datetime = "N/A",
format = 'LLL' // here is your format
) => {
return moment(datetime).isValid()
? moment(datetime).format(format)
: datetime;
};
So -- Heroku is returning the correct UTC local time, as of this writing it is 2021-10-12T19:36:00.000Z.
You're asking Heroku to interpret 2012-10-12 13:12 as a date, but you're not specifying what timezone it should use, so it defaults to its own local time of UTC.
Everything here is working as expected.
What you I think are implicitly asking is that you want it to interpret 13:12 as being in your local time. However, Heroku has no way of knowing what your local time is, so you'll need to track the timezone of events in your database.
The only reason this is working locally is because your local server happens to be in the same timezone as you -- if I were to connect to your local server from my timezone, I'd experience the same problem.
The first four lines of code seem to be an attempt to create a Date and set the seconds and milliseconds to zero. That can be done as:
let d = new Date();
d.setSeconds(0,0);
which will set the seconds and milliseconds to zero.
I don't know what you think the following does:
const currentParsedDateToUTC = Date.parse(currentDateFormatted.toUTCString());
but an identical result is given by:
d.getTime();
which is actually the value returned in the previous call to setSeconds. So the first 5 lines of code reduce to:
let currentParsedDateToUTC = new Date().setSeconds(0,0);
Then in:
const eventDate = new Date(`${event.date} ${event.endTime}`);
A timestamp in the format d/m/y H:m is parsed using the built–in parser, which is a bad idea, see Why does Date.parse give incorrect results?. You can use a library instead or just write a 2 line function to do the job.
Then again there is:
const eventParsedDateToUTC = Date.parse(eventDate.toUTCString());
which is simpley:
const eventParsedDateToUTC = eventDate.getTime();
Finally there is:
const isExpired = (currentParsedDateToUTC > eventParsedDateToUTC);
comparison operators will coerce Dates to number for you, so you can leave the values as Dates.
A function to do the job is:
// eventDate is UTC timestamp in m/d/y H:m format
function isExpired(eventDate) {
// Parse eventDate as UTC
let [M,D,Y,H,m] = eventDate.split(/\W/);
let eventD = new Date(Date.UTC(Y, M-1, D, H, m));
// return true if has passed (minute precision)
return eventD < new Date().setSeconds(0,0);
}
// Event dates (UTC)
['10/12/2021 12:00', // 12 Oct 2021 12:00
'10/13/2021 12:00', // 13 Oct 2021 12:00
'10/13/2022 12:00', // 13 Oct 2022 12:00
].forEach(d =>
console.log(d + ' has' + (isExpired(d)? '':' not') + ' Expired')
);
Where you could use the value returned by Date.UTC(Y, M-1, D, H, m) without conversion to Date so the last two lines could be:
return Date.UTC(Y, M-1, D, H, m) < new Date().setSeconds(0,0);
but it's a bit more semantic (if unnecessary) to use a Date. :-)

convert date time to utc format

I have to convert local date and time to utc format.
Therefore if I have date as 2021-08-11 (YYYY-MM-DD) and time as 2:40 PM, then slot date time should be 2021-08-11T09:10:00.000Z.
I have tried multiple things, but failed
const dateTimeInUTC = moment(
`${formattedDate} ${formatTime}`,
'YYYY-MM-DD HH:mm:ss'
).toISOString();
above code resulted me => 2021-08-10T21:10:00.000Z (which is +5:30 more)
Also, tried following
const formatted = formattedDate + " " +formatTime (2021-08-11 02:40 PM)
const result = new Date(formatted).toISOString();
this gave me
Range error :Invalid Date
However, this works as expected in console, but gives error in mobile.
I tested it now, convert - to / in date format then it will work fine in react native both on browser console and mobile. for more info you can check that link
var isoDateString = new Date('2021/08/11 12:00 pm').toISOString();
console.log(isoDateString);
If you want to use your date format (date witn -) then you to add T instead of space and the time should be on 24 hour scale
like
var isoDateString = new Date('2021-08-11T13:00').toISOString();
this solution will also work for you.
thanks
you can try that
var isoDateString = new Date('2021-08-11 2:40').toISOString();
console.log(isoDateString);
If you want to covert current System Time to UTC then Do :
const dateTimeInUTC = new Date().toUTCString();
console.log(dateTimeInUTC);
Or if you want convert any specific Date-Time to UTC then Do :
const dateTimeInUTC = new Date("October 13, 2000 00:45:00").toUTCString();
console.log(dateTimeInUTC);

Convert timestamp to local timezone in React or JavaScript

I'm getting a timestamp from an API that uses the UTC timezone and my timezone is UTC+2 I am also using timeago-react package to display time ago for certain data generated by the API
const timestamp = blocks && blocks.block.timestamp; // getting data from API
let time = new Date(timestamp);
<p className="text-sm font-light">
<TimeAgo datetime={time} locale="en_US" />
</p>
The issue I'm having is that the API is returning a timestamp of 11AM and my since my timezone is UTC+2 it's 1PM for me, the issue here is that 11AM UTC = 1PM for users with UTC+2 timezone but on time-ago it shows that the data has been generated 2hours ago which is incorrect. It was generated the moment I called that API.
Is there any workaround for this? So that it automatically calculates the time and converts it to whatever timezone the user has
Thanks for the answer guys, after doing some research I was able to achieve it with vanilla JS using this:
const fixDate = (date) => {
let dateLocal = new Date(date);
let newDate = new Date(
dateLocal.getTime() - dateLocal.getTimezoneOffset() * 60 * 1000
);
return newDate;
};
Use moment.js
With moment.js you will be able to get the user timezone e.g 'America/Los_Angeles' and convert any existing timestamp to the specified timezone. Much more readable and maintain-able compared to using JS Date.
In your case the code should be something like this
var timezone = moment.tz.guess();
var now = moment();
var la_now = now.tz('America/Los_Angeles');
// print using la_now.format('YYYY-MM-DD HH:mm:ss');

How to create Date on server(there utc timezone) and correct display on client?

We escape of using moment now and use date-fns instead. In some places we still use moment on front.
Example of code on server
//date in yyyy/mm/dd format in query params
startOfDay = StartOfDay(new Date(date));
return startOfDay
And when I display this date on front, she changes to local timezone(-4 hours). If i use date-fns-tz and convert to Canada timezone, I will get date with -4 hours and after display -4 hours more. How to resole this issue? I need to add 4 hours to date for my current timeZone. My utcOffset = 4.
Although I am not sure what function your are currently using from date-fns-ts, what has worked for me is to use utcToZonedTime(). This function gets
a date/time in the local time of any time zone from UTC time
import { utcToZonedTime } from 'date-fns-tz'
const now = new Date() // UTC
const nowCustomTimeZone = utcToZonedTime(now, 'Europe/Amsterdam')

Date in Javascript countdown

I am trying to make countdown for website. I have simple javascript code as below. Last line in code gives output 5 where it should give output zero as I have not assigned any hour value to it. And as a result my countdown stops 5 hours late then exact time I want it to stop.
var date1 = new Date("2019-12-09");
document.write(date1.getHours());
You can use getTimezoneOffset() and then subtract it off:
var date1 = new Date("2019-12-09");
console.log(date1.getHours() + date1.getTimezoneOffset() / 60);
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset
The problem here is that when you create the Date without specifying the timezone, it will treat it as if the hours/minutes/seconds were set to zero and then the whole date was converted to your local timezone (timezone of the browser to be specific). Depending on where you are in the world, it can be many hours off the mark. Because of that, every time you need to compare two dates (either for countown or anything else), you have to either use UTC methods or make sure you specify the timezone on both dates explicitly:
const timeZero = new Date('01 Jan 1970 00:00:00 GMT') // <<- explicit GMT timezone
const isoTimeZero = new Date('1970-01-01T00:00:00.000Z') // ISO format of the same
...
const today = new Date();
const utcDateStr = `${today.getUTCFullYear()}-${today.getUTCMonth()+1}-${today.getUTCDate()} 00:00:00.000 GMT`
const utcDate = new Date(utcDateStr)
const offsetInMillisec = utcDate - timeZero // You can calculate hours/munites left to zero as needed
This example ignores hours/minutes/seconds - they are easy to add in the same fashion as the date. The key is to always use the same timezone for both days, preferably UTC
Alternatively, you may want to consider switching to moment.js and saving yourself lots of hassle :)

Categories