What are the differences between the way we construct moment timezone? - javascript

moment("2014-06-01T12:00:00Z").tz("America/Los_Angeles") vs moment.tz("2014-06-01T12:00:00Z", "America/Los_Angeles")
According to https://momentjs.com/timezone/ the example show both but it didnt explain which way is preferred.

I agree that moment-timezone examples are a bit misleading, please note that moment.tz is for parsing input using given zone:
The moment.tz constructor takes all the same arguments as the moment constructor, but uses the last argument as a time zone identifier.
while tz() is to convert a moment object to a given timezone.
For "2014-06-01T12:00:00Z" both moment("2014-06-01T12:00:00Z").tz("America/Los_Angeles") and moment.tz("2014-06-01T12:00:00Z", "America/Los_Angeles") give the same result because the input contains the Z that stands for +00:00 offset.
Note that as stated by Matt Johnson (momentjs team member and date/timezone guru) in this comment:
because the input contains the Z, it will indeed be treated as UTC and converted with just moment.tz(input, zone). It's slightly bad form though, as just dropping the Z will change the behavior
So my suggestions is to use moment.utc to parse UTC inputs and then convert to desired timezone using tz(). See this related question.
Here a couple of examples of using different approaches for parsing different inputs:
// UTC input
console.log( moment("2014-06-01T12:00:00Z").tz("America/Los_Angeles").format() );
console.log( moment.tz("2014-06-01T12:00:00Z", "America/Los_Angeles").format() );
// No Z in the input (no UTC)
console.log( moment("2014-06-01T12:00:00").tz("America/Los_Angeles").format() );
console.log( moment.tz("2014-06-01T12:00:00", "America/Los_Angeles").format() );
// My suggested way
console.log( moment.utc("2014-06-01T12:00:00Z").tz("America/Los_Angeles").format() );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data-2012-2022.min.js"></script>

Related

How to output date/time in moment without timezone shift

I have a timestamp from the backend and I want to display it with momentjs per console.log() without timeshifting and completly indepented from my browsers timezone. I read many posts on stackoverflow but nothing works. All of my outputs have some timezone included.
let timestamp = "2019-11-19T07:05:00+01:00";
console.log(moment(timestamp).toISOString(true));
console.log(moment.utc(timestamp).format());
console.log(moment.utc(timestamp).toISOString(true));
console.log(moment.parseZone(timestamp).format());
console.log(moment.parseZone(timestamp).local().format());
console.log(moment.parseZone(timestamp).utc().format());
console.log(moment(timestamp).utcOffset(timestamp).toISOString(true));
console.log(moment.tz(timestamp, 'Europe/Berlin').toISOString(true));
console.log(moment.tz(timestamp, 'Europe/Berlin').format());
console.log(moment.tz(timestamp, 'Europe/Berlin').unix());
console.log(moment.parseZone(timestamp).format('MM/DD/YYYY HH:mm:ss'));
console.log(moment(timestamp).utcOffset("+0100").format('YYYY-MM-DD hh:mm:ss'));
expected output:
2019-11-19T07:05:00Z
The Timezone of the timestamp is: Europe/Berlin
My Browsers timezone is switched to something different.
I don't understand why this simple problem has no easy solution. :)
To meet the requirement you described (keeping the local time while changing the offset) you can do the following:
var result = moment.parseZone("2019-11-19T07:05:00+01:00").utcOffset(0, true).format();
console.log(result); //=> "2019-11-19T07:05:00Z"
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
Step by step explained:
moment.parseZone("2019-11-19T07:05:00+01:00") // Parses the string, retaining the offset provided
.utcOffset(0, true) // sets the offset to zero while keeping the local time
.format() // formats the output, using Z to represent UTC
However - You should recognize that these are not the same moments in time. The output timestamp is one hour earlier than the input timestamp. This is explained in the documentation as follows (emphasis mine):
The utcOffset function has an optional second parameter which
accepts a boolean value indicating whether to keep the existing time
of day.
Passing false (the default) will keep the same instant in Universal Time, but the local time will change.
Passing true will keep the same local time, but at the expense of choosing a different point in Universal Time.
Thus, it is usually the wrong choice when you already have a specific point in time, either in UTC or as an offset from UTC (like your example input value).
Instead, you should expect that converting from local time to UTC will indeed change the date and time portion of the timestamp. You can use .utcOffset(0, false), or .utcOffset(0), or simply .utc() to do the conversion correctly.

Localized short time string using moment.js

How do I get time string from moment.js object with respect to current locale?
moment().format('HH:mm')
always get the same result regardless of localization.
I want similar result as I would use in angular using shortTime:
formatDate(new Date(), 'shortTime'): // HH:mm, resp hh:mm a
You can simply use Localized formats listed in format() docs
Because preferred formatting differs based on locale, there are a few tokens that can be used to format a moment based on its locale.
There are upper and lower case variations on the same formats. The lowercase version is intended to be the shortened version of its uppercase counterpart.
Here a live sample:
console.log( moment().format('LT') );
moment.locale('it');
console.log( moment().format('LT') );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment-with-locales.min.js"></script>

Difference between moment.utc(date) and moment(date).utc()

Trying to understand the behaviour and difference between:
moment.utc(date) and moment(date).utc()
Using '2018-05-31' as a param:
moment.utc('2018-05-31').format() will give:
‌2018-05-31T00:00:00Z
while moment('2018-05-31').utc().format() will give:
2018-05-31T04:00:00Z
I am executing both in EST timezone.
The first moment.utc(String) parses your string as UTC, while the latter converts your moment instance to UTC mode.
By default, moment parses and displays in local time.
If you want to parse or display a moment in UTC, you can use moment.utc() instead of moment().
This brings us to an interesting feature of Moment.js. UTC mode.
See Local vs UTC vs Offset guide to learn more about UTC mode and local mode.
console.log( moment.utc('2018-05-31').format() );
console.log( moment('2018-05-31').utc().format() );
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>

Detect if string is a Date with an exact given format

I'd like to check whether a string does represent a Date with an given format.
I tried Date.parse(string, format) but it parses the string to date even if it's in a whole different format. E.g.:
Date.parse("2015-07-04T23:10:00.000+02:00", "yyyy-MM-ddTHH:mm:ss.SSSZ") // Parsed as a date
Date.parse("2000", "yyyy-MM-ddTHH:mm:ss.SSSZ") // Parsed as a date also`
I don't want to parse the second row as a date, because its not in the required format.
I also tried Date.parseExact() method of Date.js but it didn't parsed the date if I provided a timezone and a format like above.
The right solution was based on RobG's comment: (but thanks to everyone for helping me)
moment("2015-07-04T23:10:00.000+02:00", "yyyy-MM-ddTHH:mm:ss.SSSZ", true).isValid()
Every other solution succeeded the parsing even if the input was only a year which I tried to avoid. The last parameter "true" stands for the "strict" parsing which provides exactly the output that I was looking for.
You can leverage MomentJS and its function .format()
How does it work? here is the documentation, it's fairly simple, you wanna use your string in combination with the format string.
MomentJS .format()
And here is the quick demo Fiddle:
var myString = "2015-07-04T23:10:00.000+02:00";
var formatString = "yyyy-MM-ddTHH:mm:ss.SSSZ";
if (moment(myString, formatString)._i == myString) console.log("GOOD");
1-liner with momentJS
I basically format your string in targeted format then check if the result matches your string.
Worth noting is that MomentJS is (IMHO) the best date and time lib for JS. I never found a reason to venture beyond it since I discovered it, after using some of the less capable libs in the past.
If you don't wanna use lib, making a regex to suit your needs is a viable alternative of similar length.
Altho, if you intend to work with a lot of dates/times, MomentJS is still a way to go as it offers so many useful things which cannot be done by regexes alone.
Why not use regular expression to check if input matches the format and parse it if it does?
reg=new RegExp(/[0-9]{4}\-[0-9]{2}\-[0-9]{2}T[0-9]{2}\:[0-9]{2}\:[0-9]{2}\.[0-9]{3}\+[0-9]{2}\:[0-9]{2}/);
str="2015-07-04T23:10:00.000+02:00";
date=new Date(str);
if(str.match(reg) && date.toString()!='Invalid Date')
{
Date.parse(str);
}
Edited to add date check.

Get the given date format (the string specifying the format) in javascript or momentjs

Given a datestring, how can I get the format string describing that datestring?
Put another way, how can I get the format string that Date() or MomentJS (might be different for each, that's fine) would use to parse that datestring if one didn't pass an explicit format to use?
So given '2016-01-01' it should output something like 'YYYY-MM-DD', for example.
(I am aware this is a simple question and may have an answer somewhere, but it is difficult to word concisely, so I could only find questions and answers about how to parse datestrings or how to display dates. None about how to output the format itself.)
Consolidating information from Matt Johnson's answer, some comments, and my own contribution.
With Moment.js (version 2.10.7+), you can use the Creation Data API. Something like this in Node.js:
moment('2016-01-01 00:00:00').creationData().format
outputs
'YYYY-MM-DD HH:mm:ss'
Just as any date parsing is, there is ambiguity about the format of many datestrings due to things such as locale (the order of months and days are switched between the US and Europe, for example). But the above method is sufficient for me.
You can't, without having additional information, such as the locale. For example, 01/12/16 could be Jan 12, 2016, December 1, 2016, or December 16, 2001.
Even when you know the locale, there are several places in the real world where more than one date format is used, depending on context.
See https://en.wikipedia.org/wiki/Date_format_by_country
However, if you are just trying to determine which one of multiple known formats was used to parse the input string, moment has an API for that called Creation Data. For example:
var m = moment("2016/06/10", ["YYYY-MM-DD", "MM/DD/YYYY"], true);
var f = m.creationData().format; // "MM/DD/YYYY"

Categories