I am getting 4 dates as inputs mentioned below from an external source.
Dates with time element:
"InitialDate": "2019-02-19T12:03:22.129Z",
"updateDate": "2019-02-28T05:26:57.115Z",
Dates without time element:
"startDate": "2019-02-18",
"endDate": "2020-02-16",
I am coverting InitialDate and updateDate and creating actualInitDatE out of them using a moment format as below, as they are getting time element also in it.
I don't want time element and i only want date elements of all the 4 dates.
const actualInitDatE = moment(InitialDate).format('MM-DD-YYYY') ||
moment(updateDate).format('MM-DD-YYYY');
Now, I am converting the startDate and endDate which are having only date element in it (and no time element) and finally creating actualStartDate and actualEndDateW variables,
const actualStartDateW = moment(startDate).format('MM-DD-YYYY');
const actualEndDateW = moment(endDate).format('MM-DD-YYYY');
Now I am comparing them with the below logic and is working fine in IST,
if (actualInitDatE >= actualStartDateW && actualInitDatE <= actualEndDateW) {
console.log('Compared and True');
}
My Doubt is will this work correctly in UTC and other time zones as well? I am doubtful because some of the dates have time elements and some of them have only the date elements.
I have gone through this and implemented the approach. Is this approach is correct or do we need to use any offset?
javascript Date timezone issue
Can someone help me in this regard and let me know if this code works across timeZones?
I believe the core issue here is that you must specify a timezone for startDate and endDate. If you don't, moment.js will assume local time, for example IST or let's say you were in the US, Pacific time. The problem with this approach is that the code will give inconsistent results (depending on the machine).
You can demonstrate this by running the snippet below in your browser (Chrome is best) and changing your machine timezone. You'll see that parsing the startDate (and endDate) would result in different times depending on your timezone.
So the combination of a timestamp and a timezone give us a clear, unambiguous point in time for the most robust code. If we don't set a timezone when parsing the start and end date, the code could give a different result depending on the machine it is running on.
The best approach is to specify what timezone the startDate and endDate are in, e.g. are they in IST, or in UTC?
This way you can be sure your dates will parse consistently.
I would also suggest creating a function, say, parseDate that accepts a datestring, a format, and a timezone. This is makes all assumptions clear to anyone who reads the code.
There is no issue with InitialDate or updateDate, since they are specified as UTC times (the Z timezone specifier), so they are both clear and unambiguous.
const dates = {
startDate: "2019-02-18",
endDate: "2020-02-16"
}
const startDateNoTimezoneSpecified = moment(dates.startDate);
console.log("StartDate (No Timezone Specified):", startDateNoTimezoneSpecified.toISOString());
function parseDate(dateString, format, timezone) {
return moment.tz(dateString, format, timezone)
}
// Parse start date, assuming it is in IST (I'm assuimg IST refers to India Standard Time , if it's Israel Standard Time replace with Asia/Jerusalem!
console.log("Parse date result (IST):", parseDate(dates.startDate, "YYYY-MM-DD","Asia/Kolkata").toISOString());
console.log("Parse date result (UTC):", parseDate(dates.startDate, "YYYY-MM-DD","UTC").toISOString());
// You can also use moment.utc instead of moment.tz(date, "UTC").. it's simpler!
const startDateUTC = moment.utc(dates.startDate);
console.log("StartDate (UTC (moment.utc)):", startDateUTC.toISOString());
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://momentjs.com/downloads/moment-timezone-with-data-1970-2030.js"></script>
You seem to be over complicating things.
Your conversion of UTC timestamps to local dates is OK, but the format doesn't make sense. MM-DD-YYYY is pretty useless for anything, I'd suggest using ISO 8601 YYYY-MM-DD.
Date-only timestamps should be treated as local, so no conversion is necessary for the second two dates. Using ISO 8601 format, the strings can be compared directly:
let initialDate = '2019-02-19T12:03:22.129Z';
let updateDate = '2019-02-28T05:26:57.115Z';
// Get local date in required format
let actualInitDatE = moment(initialDate || updateDate).format('YYYY-MM-DD');
// Use these as they are
let startDate = '2019-02-18';
let endDate = '2020-02-16';
if (actualInitDatE >= startDate &&
actualInitDatE <= endDate) {
console.log('Compared and True');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
You can also keep the values as moment objects after setting them to the start of the day and use various moment methods for comparison, but I think the string version is pretty simple so why make it harder than it has to be?
Whether "this code works across timeZones" is unknown as you haven't explained what you are actually trying to achieve.
Related
I've got a form where I input an event that starts at a certain time. Let's say 9am.
To assign a date/time object I'm using MomentJs. The issue comes when displaying it in different time-zones.
In London will show up 9am as intended - in Kiev will show 11am.
How can I make MomentJS and the browser ignore which timezone is relevant for the user, and just displaying the time I'm giving?
Here's my code:
<p>
Start time:
{moment(event.startDate).format("HH:mm")}
</p>
Assuming you have stored the date as utc (which in this case you probably should have), you could use the following:
moment.utc(event.startDate).format("HH:mm")
Let me provide an alternative answer in Vanilla JavaScript. If you want to make it timezone 'neutral', you can first convert it to UTC using toISOString().
const current = new Date();
const utcCurrent = current.toISOString();
console.log(utcCurrent);
If you want to convert it to a specific timezone, such as London, you can use toLocaleString(). Do take note of the browser support for the timezone though.
const londonTime = new Date().toLocaleString('en-US', { timeZone: 'Europe/London' })
console.log(londonTime);
What you want is a normalized Datetime. This can get a little confusing since the concept of timezones is a rather arbitrary construct.
I like to think of Datetime values as "absolute" and "relative". An "absolute" Datetime is one that is true regardless of which timezone you're in. The most common example of these are UTC(+000) and UNIX Time (also known as Unix epoch, POSIX Time or Unix Timestampe).
UTC is pretty obvious. Its the current time at +000 timezone. UNIX time is a bit more interesting. It represents the number of seconds that have elapsed since January 1, 1970.
You should always store data, in both client and backend, as an "absolute" time. My preference is UNIX time since its represented as a single integer (nice and clean).
moment.js does this for you. When you instantiate your moment object, you can use:
var date = moment.utc(utcString)
or for Unix Time
var date = moment.unix(unixInt)
You can then use this object to display the date in any form you wish:
console.log(date.tz.("America/Toronto"))
The only way I could solve this is by removing the timezone and milliseconds info from the string. I used date-fns lib but I imagine moment will work the same way.
import { format } from 'date-fns'
const myDateTimeString = '2022-02-22T19:55:00.000+01:00'
const dateTimeWithoutTimezone = myDateTimeString.slice(0, 16) // <- 2022-02-22T19:55
format(new Date(dateTimeWithoutTimezone), 'HH:mm')
Hi im using moment js to convert this string 20:00 I tried:
var a = moment("20:00", "HH:mm")
console.log(a.format()) // 2016-09-08T20:00:00+01:00
the problem when I store in mongodb it become
2016-09-10T19:00:00.000Z
I want to store 2016-09-10T20:00:00.000Z
anyway can explain why please ?
When you say that you want to store 2016-09-10T20:00:00.000Z what you are saying is that you want to assume that your date and time is UTC.
To assume that the date you are parsing is a UTC value, use moment.utc
var a = moment.utc("20:00", "HH:mm")
console.log(a.format()) // 2016-09-08T20:00:00Z
Note that when you parse a time without a date, moment assumes the current date. This may not be the behavior that you want.
I'm also not sure if you want a UTC date (which is what you are saying), or a local date without an offset indicator. If you want a local date without an offset indicator, simply use a format without an offset:
moment.utc("20:00", "HH:mm").format('YYYY-MM-DDTHH:mm:ss.SSS')
"2016-09-08T20:00:00.000"
If you are dealing with local dates that do not have a time zone association, I recommend using moment.utc to parse, as this will ensure that the time does not get shifted to account for DST in the current time zone.
For more information about how to parse dates into the time zone or offset that you would like in moment, see my blog post on the subject.
This it how it should look:
var a = moment("20:00", "HH:mm")
console.log(a.utcOffset('+0000').format())
<script src="http://momentjs.com/downloads/moment.min.js"></script>
Doe, the problem is that you are using timezones when you create the date.
MomentJS uses your current timezone automatically.
Mongo however saves the time as it would be in another timezone.
Therefore, if you want the two strings to format the same way, you need to set the timezone.
I do let fullcalendar initialize normally. So it represents current date. (Midnight->midnight, 1day, 1h slots)
From some other datasource I get data with timestamps. The format is "YYYY-MM-DD HH:mm" (transmitted as a string, no timezone information)
So I convert that string to a moment object and test against fullcalendar.start and .end to see if it is within.
moment("2016-04-07 00:00") == $('#calendar').fullCalendar('getView').end
This results in false though the following command
$('#calendar').fullCalendar('getView').end.format("YYYY-MM-DD HH:mm")
returns
"2016-04-07 00:00"
I also tried to compare with diff
moment("2016-04-07 00:00").diff( $('#calendar').fullCalendar('getView').end,"minutes")
which returns
120
Some research on the calendars.end object in Chrome Dev Tools revealed that it internally is represented as
2016-04-07 02:00 GMT+0200
This looks strange to me. I am in timezone 2h ahead of GMT. So it should correctly say 2016-04-07 00:00 GMT+0200, should it not?
This also explains why the diff test above resulted in 120 minutes.
Can someone help? I do not get where the conversion problem comes from. I am using only dates with no timezone information. And as said above, fullcalendar initalizes with no gotodate information and shows a time bar from 00:00 to 00:00. So why does it come that there is this 2h difference?
Thanks a lot. I do understand things a lot better now.
Some of the dates I tried to compare were 'now'. I got 'now' by
var n = moment()
That turned out to be a date time including my timezone.
E.g. moment().format() resulted in '2016-04-07 00:00 GMT+0200' and I now see how this went wrong excepting a comparison against full calendar.end to be true but it was false as '2016-04-07 00:00 GMT+0200' is '2016-04-06 22:00' at UTC.
As
moment.utc()
does not work, I know ended up with using
moment.utc(moment().format('YYYY-MM-DD HH:mm'))
This now seems to work as this treats my local time as it would be the 'numerical same time' at UTC.. thus matching with how fullcalendar handles times internally (ambiguously-zones moments).
Thanks
A few things:
The timezone parameter controls how FullCalendar works with time zones.
By default, FullCalendar uses "ambiguously-zoned moments". These are customizations to moment.js made within fullCalendar. The docs state:
The moment object has also been extended to represent a date with no specified timezone. Under the hood, these moments are represented in UTC-mode.
Thus, to compare dates in this mode, treat them as if they were in UTC.
moment.utc("2016-04-07 00:00")
To compare moments, use the moment query functions, isSame, isBefore, isAfter, isSameOrBefore, isSameOrAfter, and isBetween.
In this case, since FullCalendar's start is inclusive but the end date is exclusive, you probably want to compare like this:
var cal = $('#calendar').fullCalendar('getView');
var start = cal.start;
var end = cal.end;
var m = moment.utc("2016-04-07 00:00"); // your input
var between = m.isSameOrAfter(start) && m.isBefore(end);
Note that there's an pending enhancement to moment's isBetween functionality for a future release that will give you control of exclusivity, but currently isBetween is fully inclusive, so you have to use the combination of functions shown here.
I always get the wrong date when I use var date = new Date(timestring), there is always +2 GMT hours.
var unsortedPlayTimes =
[{date:'2014-08-11T09:30:00'},
{date:'2014-08-11T08:30:00'},
{date:'2014-08-11T08:15:00'},
{date:'2014-08-11T08:45:00'},
{date:'2014-08-11T12:30:00'},
{date:'2014-08-11T10:30:00'},
{date:'2014-08-11T11:30:00'},
{date:'2014-08-11T07:30:00'},
{date:'2014-08-11T13:00:00'},
{date:'2014-08-11T23:00:00'},
{date:'2014-08-12T00:00:00'},
{date:'2014-08-12T01:00:00'},
{date:'2014-08-12T05:00:00'},
{date:'2014-08-12T09:00:00'},
{date:'2014-08-11T14:00:00'},
{date:'2014-08-11T18:30:00'},
{date:'2014-08-11T13:00:00'}];
function SortandFilterPlayTimes (allPlayTimes) {
var filteredPlayTimes = [];
$.each(allPlayTimes, function(index, value) {
var date = new Date(value.date);
if ($.inArray(date,filteredPlayTimes) === -1) {
filteredPlayTimes.push(date);
}
});
};
Why is JavaScript always adding this +2 hours ?
You're using the ISO-8601 formatting of dates while omitting the timezone, this makes the parsing consider the timezone as UTC in ES5 (this will be different in ES6 : strings in ISO format will be considered as local too when the timezone isn't provided).
If you want the date to be parsed with your local timezone in ES5, you might change the format to a not ISO one :
var date = new Date(value.date.replace(/T/,' '));
But you might also want to check you really want the date to be parsed depending on the user's timezone, this is most often a bad idea. The usual good solution is to send the timezone or to send the date as a unix timestamp (what you get with date.getTime()).
You are parsing ISO-8601 timestamps without timezone information, thus a UTC timezone is assumed, but Date.prototype.toString() will provide a string representation of this timestamp in your current timezone which means that if you are in the UTC+2 timezone you will notice a shift by two hours.
I'm guessing your project is hosted on a server that has a +2 hours time difference with your local system, thus giving you a time you are not expecting. Is your server in a different country?
Using Moment.js I can't transform a correct moment object to a date object with timezones. I can't get the correct date.
Example:
var oldDate = new Date(),
momentObj = moment(oldDate).tz("MST7MDT"),
newDate = momentObj.toDate();
console.log("start date " + oldDate)
console.log("Format from moment with offset " + momentObj.format())
console.log("Format from moment without offset " + momentObj.utc().format())
console.log("(Date object) Time with offset " + newDate)
console.log("(Date object) Time without offset "+ moment.utc(newDate).toDate())
Use this to transform a moment object into a date object:
From http://momentjs.com/docs/#/displaying/as-javascript-date/
moment().toDate();
Yields:
Tue Nov 04 2014 14:04:01 GMT-0600 (CST)
As long as you have initialized moment-timezone with the data for the zones you want, your code works as expected.
You are correctly converting the moment to the time zone, which is reflected in the second line of output from momentObj.format().
Switching to UTC doesn't just drop the offset, it changes back to the UTC time zone. If you're going to do that, you don't need the original .tz() call at all. You could just do moment.utc().
Perhaps you are just trying to change the output format string? If so, just specify the parameters you want to the format method:
momentObj.format("YYYY-MM-DD HH:mm:ss")
Regarding the last to lines of your code - when you go back to a Date object using toDate(), you are giving up the behavior of moment.js and going back to JavaScript's behavior. A JavaScript Date object will always be printed in the local time zone of the computer it's running on. There's nothing moment.js can do about that.
A couple of other little things:
While the moment constructor can take a Date, it is usually best to not use one. For "now", don't use moment(new Date()). Instead, just use moment(). Both will work but it's unnecessarily redundant. If you are parsing from a string, pass that string directly into moment. Don't try to parse it to a Date first. You will find moment's parser to be much more reliable.
Time Zones like MST7MDT are there for backwards compatibility reasons. They stem from POSIX style time zones, and only a few of them are in the TZDB data. Unless absolutely necessary, you should use a key such as America/Denver.
.toDate did not really work for me, So, Here is what i did :
futureStartAtDate = new Date(moment().locale("en").add(1, 'd').format("MMM DD, YYYY HH:MM"))
hope this helps
Since momentjs has no control over javascript date object I found a work around to this.
const currentTime = new Date();
const convertTime = moment(currentTime).tz(timezone).format("YYYY-MM-DD HH:mm:ss");
const convertTimeObject = new Date(convertTime);
This will give you a javascript date object with the converted time
The question is a little obscure. I ll do my best to explain this. First you should understand how to use moment-timezone. According to this answer here TypeError: moment().tz is not a function, you have to import moment from moment-timezone instead of the default moment (ofcourse you will have to npm install moment-timezone first!). For the sake of clarity,
const moment=require('moment-timezone')//import from moment-timezone
Now in order to use the timezone feature, use moment.tz("date_string/moment()","time_zone") (visit https://momentjs.com/timezone/ for more details). This function will return a moment object with a particular time zone. For the sake of clarity,
var newYork= moment.tz("2014-06-01 12:00", "America/New_York");/*this code will consider NewYork as the timezone.*/
Now when you try to convert newYork (the moment object) with moment's toDate() (ISO 8601 format conversion) you will get the time of Greenwich,UK. For more details, go through this article https://www.nhc.noaa.gov/aboututc.shtml, about UTC. However if you just want your local time in this format (New York time, according to this example), just add the method .utc(true) ,with the arg true, to your moment object. For the sake of clarity,
newYork.toDate()//will give you the Greenwich ,UK, time.
newYork.utc(true).toDate()//will give you the local time. according to the moment.tz method arg we specified above, it is 12:00.you can ofcourse change this by using moment()
In short, moment.tz considers the time zone you specify and compares your local time with the time in Greenwich to give you a result. I hope this was useful.
To convert any date, for example utc:
moment( moment().utc().format( "YYYY-MM-DD HH:mm:ss" )).toDate()
let dateVar = moment('any date value');
let newDateVar = dateVar.utc().format();
nice and clean!!!!
I needed to have timezone information in my date string. I was originally using moment.tz(dateStr, 'America/New_York').toString(); but then I started getting errors about feeding that string back into moment.
I tried the moment.tz(dateStr, 'America/New_York').toDate(); but then I lost timezone information which I needed.
The only solution that returned a usable date string with timezone that could be fed back into moment was moment.tz(dateStr, 'America/New_York').format();
try (without format step)
new Date(moment())
var d = moment.tz("2019-04-15 12:00", "America/New_York");
console.log( new Date(d) );
console.log( new Date(moment()) );
<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.23/moment-timezone-with-data.min.js"></script>
moment has updated the js lib as of 06/2018.
var newYork = moment.tz("2014-06-01 12:00", "America/New_York");
var losAngeles = newYork.clone().tz("America/Los_Angeles");
var london = newYork.clone().tz("Europe/London");
newYork.format(); // 2014-06-01T12:00:00-04:00
losAngeles.format(); // 2014-06-01T09:00:00-07:00
london.format(); // 2014-06-01T17:00:00+01:00
if you have freedom to use Angular5+, then better use datePipe feature there than the timezone function here. I have to use moment.js because my project limits to Angular2 only.
new Date(moment()) - could give error while exporting the data column in excel
use
moment.toDate() - doesn't give error or make exported file corrupt