In a nutshell I want moment to respect server's timezone. I've set my machine's timezone to Alaska but I'm passing a Brisbane timezone string to moment. Now I need moment.toDate to return a date instance in the same timezone as the one I pass in the moment constructor; e.g.
m = moment("2016-11-20T08:00:00+10:00")
m.format() // "2016-11-20T08:00:00+10:00"
m.toDate() // Sat Nov 19 2016 13:00:00 GMT-0900 (AKST)
I want to get a Date instance from moment that's in the input timezone; e.g. somehow get toDate to return Sun Nov 20 2016 08:00:00 GMT+1000 (AEST).
FWIW I have tried the same code with and without moment.tz.setDefault and while it correctly changes the format result, toDate always uses the machine's timezone!
Update
The reason I need this behaviour is that some JavaScript libraries and controls don't understand moment and only work with Date and the time/date gets skewed when presented back by them. One example, the one I'm currently dealing with, is jQuery UI date picker control. I want the date picker to show the current date as it's on the server (or on a specific timezone).
Thanks in advance.
The Date object represents the time in UTC internally, and can only use the time zone of the machine its running on when projected.
There's absolutely no way to produce a Date object that uses an arbitrary time zone. Any examples you may come across that try to manipulate the Date object (such by adding or subtracting time zone offsets) are fundamentally flawed.
Moment itself has great time zone support, including the moment-timezone extension for working with named time zones instead of just time zone offsets. But once you go back to a Date object - you're back at the mercy of the behavior of that object.
Sorry, but there's no way to achieve what you are asking. Perhaps you could elaborate as to why you wanted to do this, and I could recommend a workaround.
Update: With regards to your update, usually there is a mechanism for getting the value from a date picker as text, rather than as a date object. With the example of the jQuery UI date picker control, the onSelect event gives it to you as text already, or you can simply call .val() instead of .datepicker('getDate') to get the text out of the field. Once you have a textual value, you can then parse it with moment however you like.
Similarly, when setting the value, you don't necessarily need a Date object. You could just set the value of the textbox as a string, or you can pass a string to the setDate function.
In most cases, you won't have to go through a Date object. But if for some reason you do, then you'll need to artificially construct one with something crazy like:
var d = new Date(m.format('YYYY/MM/DD'));
Normally, I'd be against that - but if it's just there to get the pass a value to a UI control, then it's probably ok.
This will get you a moment in the same timezone as the moment string, but toDate is always in the local timezone.
d = "2016-11-20T08:00:00+10:00"
m = moment(d).utcOffset(d)
m.format()
m.toDate()
Related
I receive the following date from the server:
"2018-11-21 07:00:00 UTC"
Then, I convert it using userTimzone variable (since I wish the editor would use the user timezone):
dateOfAction: moment(dateOfLoss, 'YYYY-MM-DD HH:mm Z').tz(userTimzone).unix(), So dateOfAction is 1542776400. That is: Wednesday, November 21, 2018 5:00:00 AM - and so far so good. That is the dateOfAction in UTC with after right offset
I'm using react-datetime as the calendar the edit the date, using UTC.
When performing the save action, without touching the date, the calendar output is still 1542783600, but I wish to be 1542783600 - i.e the same value as in the beginning, reverting the offset at the other direction.
How can I achieve that?
A few things:
Moment doesn't map the Z token to the string "UTC". Since you're parsing in local mode, you are actually getting a moment based on the local computer's time zone rather than UTC. Thus, change the first part of your code to:
moment.utc(dateOfLoss, 'YYYY-MM-DD HH:mm [UTC]')
The brackets are to treat UTC as a literal string, which isn't strictly required so you can omit it if you like and the result will be the same.
moment.utc(dateOfLoss, 'YYYY-MM-DD HH:mm')
There's no need to call .tz(userTimezone) if you're just going to call .unix() subsequently. Unix timestamps are always UTC based. Though it's not clear why you're asking for a Unix timestamp, as react-datetime doesn't need one.
The two values you gave in the last paragraph of your question are identical, so I'm not sure specifically what you were looking for. The time you gave is indeed 1542783600, not 1542776400.
The readme file of react-datetime describes all the options you can use. You can simply pass the moment object obtained above to the value prop. You might need to use the utc or displayTimeZone props if you want to change the behavior. You might also need to call .local() or .tz(userTimezone) on the moment object before passing it in, but I'm not certain if that is required or not for this particular component.
I thought I had a handle on this, but I cant work it out.
scenario:
1) user selects a date widget which passes back a date in local timezone, lets say 10am 'Australia/Sydney'
2) user then selects a timezone that is different, by identifier 'Australia/Brisbane' (this is a different TZ and may have daylight saving etc...) lets assume its +1hr
What I want to do is have a function that takes a Date object that represents [10am 'Australia/Sydney'] and return to me a new Date that represents [10am 'Australia/Brisbane] i.e. the underlying UTC time will have shifted +1hr
function convertToTimezone(date, newTimezone) {
... what goes here? ...
return newDate;
}
Ive been mucking about with moment timezone and I cant get it to do what I want.
The moment-timezone library should make this trivial:
function convertToTimezone(date, newTimezone) {
return moment(date).tz(newTimezone);
}
Or if date is already a moment:
function convertToTimezone(date, newTimezone) {
return date.clone().tz(newTimezone);
}
See the documentation on Converting to Zone for more information.
OK, FWIW, I got an answer myself. moment.tz doesnt work as I imagined.
To summarise, I want to take a javascript Date that has a wallclock time, say '10am on the 15 sep 2018' that has been associated with a certain timezone identifier, say BrisabneOz.
And turn it into a new date that represents that same wallclock time, but in a different timezone. In otherwords, change the underlying UTC time by the amount required by the shift in timezones and/or daylight savings etc...
The way I found to do this was to get the string of the wallclock date, thus stripping any associated timezone from tbe equation, and using moment.tz to make another date object using the new different timezone. Which it can do.
The part that confused me was having to go to a string as a step - thought I could just pass in one date and get moment.tz to magic me up another date ala #Alex Taylor answer, but this doesnt actually work.
function convertDateToTimezone(date, timezone) {
const str = moment(date).format('YYYY-MM-DD HH:mm:ss');
const tzMoment = moment.tz(str, timezone.identifier)
return tzMoment.toDate()
}
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 have date and time in 2016-06-21T10:00:00-07:00 format which represets 06/21/2016 5 PM in PST, I just want to change this to 06/21/2016 5 PM in EST and vice versa. How can I do it with momentz?
JSFiddle
debugger;
var dateTime = moment('2016-06-21T10:00:00-07:00');
var newDateTime = dateTime.clone();
newDateTime.tz('US/Eastern');
//dateTime = dateTime.utc();
console.log(dateTime.utcOffset());
console.log(newDateTime.utcOffset());
console.log(newDateTime.utcOffset() - dateTime.utcOffset());
//console.log(utc.format());
dateTime = dateTime.add(newDateTime.utcOffset(), 'minutes');
console.log(dateTime.format());
console.log(new Date(Date.parse(dateTime.format())).toJSON());
EDIT:
given input = 2016-06-21T08:00:00-07:00 (PST)
expected output = 2016-06-21T08:00:00-04:00 (EST)
So when I convert that to UTC then it should become
2016-06-22T15:00:00Z for PST
2016-06-22T12:00:00Z for EST
I think you are confused about how ISO8601 format works. This format always represents local time with a time zone offset. Thus 2016-06-21T10:00:00-07:00 represents June 21 2016 at 10 AM in a timezone that is currently UTC-7 (this could be US pacific, among many others).
It sounds like you want to take the local time, but put it in a new timezone. This opens up some interesting questions about why you are receiving the date in the format that you are. If the date is meant to be interpreted as an exact point on the global timeline, then the format you are receiving it in is good. If however, the date is meant to be interpreted as a local time (not relative to UTC), it might be worth considering the possibility that the format of the date needs to be changed at the source. For instance, if you are making an ajax request to an API, and it is returning a date in this format, but that date actually has no relationship to UTC, it would be good to try to change that API to only send the local time (without the offset). If you were able to do that, then the following code would work:
moment.tz('2016-06-21T10:00:00', 'America/New_York').format()
"2016-06-21T10:00:00-04:00"
If you are unable to do that, or if the date is meant to be interpreted as an exact point on the global timeline, but you wish to ignore that in your specific use case, that can be done. You will need to specify a parse format that ignores the timezone offset on your initial time stamp. The code would be as follows:
moment.tz('2016-06-21T10:00:00-07:00', 'YYYY-MM-DDTHH:mm:ss', 'America/New_York').format()
"2016-06-21T10:00:00-04:00"
You might benefit from the material in this blog post, as it covers how ISO8601 format works, and how all of moment's constructor functions work.
Checkout moment().utcOffset() You can pass in the offset as parameter to this function and the date would use that locale.
Assuming you know beforehand the utcOffsets required which in your case are -420 and -240 or -300(EST with DayLightSaving). Below can be done
var dateTime = moment('2016-06-21T10:00:00-07:00');
dateTime.utcOffset(-420).format();
"2016-06-21T10:00:00-07:00"
dateTime.utcOffset(-240).format()
"2016-06-21T13:00:00-04:00"
NOTE: With -04:00, it should 13:00:00 and not 07:00:00 - http://www.timeanddate.com/time/zones/est
EDIT: This answer was posted to the earlier version of question, where same time was needed in different timezones. If it is incorrect, kindly please elaborate on how it is.
Thanks!
I have a form where a user can enter a date, i.e. <input type="date"> the value is submitted in yyyy-MM-dd format. When I create a Date object with the string it assumes the time zone is the one the user's browser is set to – this is the behavior I want.
I'm then using the date value to make queries against a REST API that expects ISO date/time strings. That's no problem as the toISOString function on the Date object handles everything correctly.
However, when I'm unit testing this code – setting my input to a yyyy-MM-dd string then asserting that the output is an expected ISO timestamp string the tests can only work in a particular time zone. Is there a way I can force the time zone in the test?
I've tried using Jasmine spies to do something like:
var fixedTime = moment().zone(60).toDate()
spyOn(window, 'Date').andCallFake(function() {
return fixedTime;
});
But given there are so many variants of the constructor and so many ways it gets called by moment.js this is pretty impractical and is getting me into infinite loops.
A JavaScript Date cannot be set to a particular time zone. It only knows about UTC and the computer's local time from the environment it is running on.
There are time zone libraries for javascript, but I don't think that will help you here.
First, understand that "ISO" refers to ISO8601, which is a specification that defines a collection of related formats, such as YYYY-MM-DDTHH:MM:SS.
It is a separate concept from UTC, which refers to Universal Coordinated Time. UTC is the timekeeping system that we all synchronize our clocks to, which uses GMT as its basis - that is, the time in effect at the prime meridian not adjusted for daylight saving time.
Put together, the Date.toISOString() method will return the UTC form of an ISO8601 formatted timestamp, such as 2013-09-20T01:23:45Z. The Z at the end indicates that the time is in UTC.
But a value such as 2013-09-20 is still ISO formatted - it's just that it only has precision to the whole day, which means that it can't carry any time zone information.
When you use <input type="date">, the resulting value is not a Date class. It's a string containing the ISO formatted YYYY-MM-DD. You should just pass this directly to your application.
Now if what you are looking for is the full date and time, at midnight in the local time zone, of the date selected, and adjusted to UTC, well that's a different story. It is certainly doable but you have to understand that it is not the same as just passing the calendar date.
The easiest way to do that would be with moment.js as follows:
var s = "2013-09-20"; // from your input's value property
var m = moment(s);
var result = m.toISOString(); // "2013-09-20T07:00:00.000Z"
The value is adjusted because my time zone offset is -07:00.
You can do it without moment, but you have to replace dashes with slashes or the original value will be interpreted as if it is already in UTC.
new Date(s.replace('-','/')).toISOString()