Simplest way to find out how many milliseconds until a specific time in a specific timezone (taking DST into account)? - javascript

I have a piece of code which finds the difference between two dates(in the format of yyyy-MM-dd hh:mm:ss) . This code is run in multiple servers across the globe. One of the two dates is the current time in that particular timezone where the code is being run(server time) and another is the time obtained from a database. if the difference between these two times is greater than 86400 seconds(1day), then it should print "invalid" else, it should print "valid".
Problem im facing with the code is when I run it on my local, its working fine, but when i deploy it onto a server in US, its taking GMT time into consideration and not local time.
Wherever the code is run, I want the difference between current time and time fetched from the database, and if its greater than 86400 seconds, i want to print invalid. How to achieve this in java?
PS: I tried with Date object, but its considering GMT only everywhere.

I would use GMT everywhere and only convert to the local times for display purposes.
To find the difference, convert both times to the same timezone (say GMT) and take the difference.

You can do it by the below example code.
Date date = new Date();
DateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss z");
formatter.setTimeZone(TimeZone.getTimeZone("CET"));
Date date1 = dateformat.parse(formatter.format(date));
// Set the formatter to use a different timezone
formatter.setTimeZone(TimeZone.getTimeZone("IST"));
Date date2 = dateformat.parse(formatter.format(date));
// Prints the date in the IST timezone
// System.out.println(formatter.format(date));
Now compare date1 with date2

First, I concur with Peter Lawrey's answer up there. It is usually good practice to store all time in the database for a single zone, and render it with offset for the user based upon the user's locale.
To find the difference, use the method getTime() to get the time in milliseconds from the epoch for each date. The calculation for the difference of 1 day is then 86400 * 1000 milliseconds. Or, perhaps, store the time in milliseconds from epoch in the database, and use a DB procedure/function at the time of retrieval.
Hope this helps.

Related

How to save correct time in database?

I have one object called appointment which has two properties: StartDate and EndDate.
When I make POST request I send these values using ISOString time .
this.appointment.StartDate.toISOString()
On the server-side, I received these properties with correct values. Also, it seems to be correct when I create model in order to save appointment to the database. I used .ToUniversalTime() method.
var newAppointment = new Appointment()
{
StartDate =Convert.ToDateTime(model.StartDate).ToUniversalTime(),
EndDate = Convert.ToDateTime(model.EndDate).ToUniversalTime(),
SpecialityId = speciality.Id,
LocationId = location.Id,
PatientId = patient.Id,
UserId = user.Id,
Observations = model.Observations
};
But in database I found another values. Can explain somebody why is this behaviour ?
For instance, I used 2017.09.01 11:00 for StartDate and in database i found 2017-09-01 08:00
The server and database is located in the westeurope.
A few things:
Don't call ToUniversalTime in a web application. It's designed to convert from the server's local time zone to UTC. The server's time zone should be irrelavent to your application. Web applications should never use ToUniversalTime, ToLocalTime, DateTime.Now, TimeZoneInfo.Local, DateTimeKind.Local or any other method that uses the time zone of the computer it's running on.
Ideally, on the server side, your model.StartDate and model.EndDate would already be DateTime objects, because they'd have been deserialized that way. Therefore, you probably don't need to call Convert.ToDateTime. If they are strings, then I would adjust your model class accordingly.
On the client side, assuming StartDate and EndDate are JavaScript Date objects, and they were created using local time values (that is, the time zone of the browser), when you call toISOString, you're not just getting a string in ISO 8601 format - it is also converting it from the browser's time zone to UTC.
In your example, the UTC time is 3 hours ahead of UTC for the date and time shown. From your profile, I see you are located in Romania, which is indeed UTC+3 for this date, because it is currently observing Eastern European Summer Time. When Summer Time ends (on October 29, 2017 at 04:00), it will return to UTC+2. For this reason, you cannot simply add three hours to all values.
If you want to send local time values from the client, you should send them in ISO 8601 format, without any Z or offset, for example 2017-09-01T11:00. There are several ways to achieve this:
The best way is to not have them in a Date object to begin with. For example, if your input uses the <input type="datetime-local" /> input type (as specified in HTML5), the .value property is not a Date object, but rather a string in ISO 8601 format.
If you can't avoid a Date object, then create a local ISO string, like this:
function dateToLocalISOString(date) {
var offset = date.getTimezoneOffset();
var shifted = new Date(date - offset * 60 * 1000);
return shifted.toISOString().slice(0, -1);
}
OR, using Moment.js:
moment(yourDateObject).format("YYYY-MM-DD[T]HH:mm:ss.SSS")
Lastly, you will probably read advice from others about storing these as UTC. Don't listen. The advice "always use UTC" is shortsighted. Many scenarios require local time. Scheduling appointments is a primary use case for local time. However, if you need to act on that appointment, you'll use the current UTC time, and you'll also need some information about the time zone for the appointment so you can convert from UTC to the appointment's time zone. For example, if this is something like an in-person doctor's office appointment, then it's safe to assume the time zone of the doctor's office. But if it's an appointment for an online meeting, then you'll have to capture the user's time zone separately and apply it on the back end where appropriate.
The problem is with your current timezone.
What your application does is get current timezone (+3) in this case.
Now it got your timezone but it will convert to utc time. So what will happen, your current time will be -3 hours.
If you not adjust to summer and winter time then you can simply add 3 hours to the datetime. Otherwise you have to get the offset of your timezone and add that to the current datetime value.
Take care if you use this application in different timezones. For example You life in +3 and some else life in +2 timezone.

Converting UTC milliseconds to Central Time in javascript

We have a bunch of systems events that are stored in a database with a milliseconds timestamp in UTC. In order for me to get the JSON I need, I just need to send a request like this....
http://xxx.xxx.xxx/gimmeJson?starttime=MILLISECONDS&endtime=MILLISECONDS
So when an event happened at 11:00pm CST it has been converted to the UTC millisecond equivalent and stored.
I am having a big issue wrapping my head around milliseconds because I'm thinking about it like timezones.
I saw a SO question similar to this here: How do I convert UTC/ GMT datetime to CST in Javascript? (not local, CST always) and it was close but not quite there.
If timestamps are stored in UTC milliseconds, how can I query them for their Central time equivalent? By that I mean my boss wants a report of all events that happened in the central timezone but I have to query a database that has these timestamps stored as UTC milliseconds.
Ultimately I have to come up with ** some ** number to send on a URL for UTC MILLISECONDS that is the equivalent of say "September 24, 12:00:00 Central". What compounds this issue is that the web service is fairly new and has been shown to be a bit buggy so I need to make sure I have this right.
// construct a moment object with Central time input
var m = moment('2015-01-01 00:00:00').format('x');
// convert using the TZDB identifier for GMT
m.tz('Europe/London');
// format output however you desire
var s = m.format("x");
Can someone confirm I am on the right track?
Many, many thanks in advance.
There's no such thing as milliseconds timestamp in UTC or any other timezone. Millisecond timestamps are always from 1970-01-01T00:00:00.000Z; they are zone agnostic.
In order to get the timestamp for the zone you want, simple create a Date instance and use the Date.prototype.getTime method
var cstTime = new Date('2016-09-24T12:00:00-06:00');
console.log('CST in ISO 8601:', cstTime.toISOString());
console.log('CST timestamp:', cstTime.getTime());
var localTime = new Date();
console.log('Local time in ISO 8601:', localTime.toISOString());
console.log('Local timestamp:', localTime.getTime());

How to display Datetime considering offset using MomentJS with Timezones

I'm using moment.js with timezones to create a datetime belonging to a specific timezone:
var datetime = moment.tz("2016-08-16 21:51:28","Europe/London");
Because this constructor is aware of DST (daylight saving time), moment.js will add +1 hour offset automatically. datetime.format() will show: 2016-08-16T21:51:28+01:00.
But it seems when printing the date, the offset ins't considered. E.g. datetime.format('DD.MM.YYYY - HH:mm:ss') will show: 16.08.2016 - 21:51:28 but I wan't it to show: 16.08.2016 - 22:51:28 (the time considering the DST-Offset of 1 hour). Does anyone know how to do this?
You are misinterpreting the output you're getting.
When you see +01:00 at the end of an ISO8601 timestamp, it doesn't mean that you need to add an hour. It means that timestamp given is in a local time zone that is one hour ahead of UTC at that point in time. Moment isn't adding an hour. It's simply reflecting the local time in London.
For the timestamps you provided, showing 22:51:28 would be an error. The local time in London is 21:51:28, and the equivalent UTC time is 20:51:28. You wouldn't find 22:51:28 until you went one time zone to the East, at UTC+2.
Now, if what you meant to do is convert from UTC to London time, then you need to create the input as UTC and then convert.
moment.utc("2016-08-16 21:51:28").tz("Europe/London")
Then you'd get 22:51:28 when formatting, which is the result you asked for, but this is a different point in time.

Moment.js local relative time

I have dates in my database set to Europe/London time. I am using Moment.js to show relative time e.g. "3 minutes ago". This works fine for me as I am in the same timezone, but for example, someone who is PST timezone would see "in 8 hours". How can I fix this?
My current code is like this:
$('time').text( moment( '2016-01-22 18:00:00' ).fromNow() );
To echo Jon's answer, moment's relative time functionality is strictly UTC based, so the behavior you describe won't actually happen, unless you are interpreting the original timestamp in local time.
It's hard to say if you're doing that or not, as you didn't give a sample value of the input string.
If your times are indeed UTC based, but that's not reflected in the input string, then use moment.utc instead of just moment.
And no, London is not the same as UTC.
I believe that the best approach is to store the date in UTC and then convert this to the local time zone for display. Note that this is not necessarily the same as London time because UTC does away with daylight savings time nonsense. You can do everything that you need with the date class provided the time stamp stored in the database does not have to deal with the vagaries of time zone and DST. The date class maintains its own epoch internally as milliseconds elapsed since midnight 1 January 1970 UTC. You can evaluate the difference between two Date objects as follows:
var agora = Date.now();
var stored = ... // the date that was stored in your database
var diff_msec = agora.getTime() - stored.getTime();
Knowing that the difference and that its units are milliseconds, you can convert the difference to whatever units are best for presentation.

Get unix timestamp of only date in node js

I have a problem in getting unix timestamp on only date(Without time) in node js. I tried with moment js
I have tried this,
moment.unix();// which gives,1446090606
If i use the same i php,
echo date("Y-m-d H:i:s", 1446090606);// echoes 2015-10-29 04:50:06
But actual time stamp of today's date is 1446073200
echo date("Y-m-d H:i:s", 1446073200);// echoes 2015-10-29 00:00:00
I even tried with Date() in javascript,
I referred this, this but no use.
EDIT
I even tried like this,
console.log(moment("2015-10-29 00:00:00").unix());// which gives 1446057000
echo date("Y-m-d H:i:s", 1446057000);// echoes 2015-10-28 19:30:00
It echoes yesterday's date
To summarize what i want is, timestamp of only date without time.
Thank you.
So first you need to ask yourself what you are looking for ultimately. It's really in your best interest to keep all your timestamps in standard UTC format and, if you are storing strings, use the ISO8601 standard. For fun: XKCD on ISO8601
It will make your life so much easier to pass around dates in only one format (UTC timezone / ISO8601 format if a string) until just before you display them to a user.
Only then should you format the date as a user would expect it to be formatted to represent the local time, and you should write a date formatter to ensure this conversion is always done consistently.
On the client side, convert the date to this standardized format the moment it is captured by the user and before it is sent to the server (effectively a reverse of the formatter described above).
All of your server date logic beyond that will typically be calculating time differences without needing to worry about timezone conversions. /rant
Now to discuss your question in a bit more detail and why you are facing issues.
According to moment.js docs:
By default, moment parses and displays in local time.
So when you do this:
moment.unix();
Know that this is relative to the local time. Also unix time is the number of seconds relative to one singular point in time, an epoch which happens to be January 1st, 1970 00:00:00 (when put into the UTC timezone).
To make this hit home. Use your PHP date function and input "0" as the unix timestamp. What do you get? It will depend on the default timezone set in your PHP environment.
For me, the output of the online PHP sandbox I used:
<?php echo date('Y-m-d H:i:s', 0); ?>
// 1969-12-31 16:00:00
Uh oh. What's going on here? That's before epoch time, and I definitely just put a big fat ZERO there.
So this is the importance of keeping your date formats consistent across the board. It will make your life a lot easier.
Here is what you need to do and why:
1. Get the local date's midnight. This is the first piece of information you need to capture in a moment variable because it represents what you are interested in. Once you have that, the rest is just understanding how to format that date how you want.
var lastLocalMidnight = moment().startOf('day')
var lastUTCMidnight = moment.utc().startOf('day')
For the sake of argument and your understanding, I have included another variable which captures and converts "now" into the UTC timezone before getting "midnight".
So what's the difference here? Read the moment.js docs on UTC further:
Any moment created with moment.utc() will be in UTC mode, and any moment created with moment() will not.
To switch from UTC to local time, you can use moment#utc or
moment#local.
moment.js variables have timezone information self-contained within them when you perform other operations on them. It is important to distinguish the difference between this and the standard PHP Date behavior which treats dates the same (unless you explicitly say otherwise).
The timezone being used in every case needs to be known or set. Not understanding these two behaviors completely is most likely the source of your confusion.
A "date is a date is a date". A moment in time, hence the library name "moment.js". It needs to be stated or set what timezone that date is in. There are different formats to capture this information, but just understand that "2015-10-29 04:50:06" doesn't tell you anything until you know the timezone. It's basically the same as how 12:00 doesn't tell you anything until you know AM or PM (assuming you are not using military time).
2. Now that you have a midnight representation (whichever you deem is the correct one for your purposes), you can convert that to a UNIX timestamp because it is relative to a timezone you know you are interested in and represents the exact moment you want.
console.log(lastLocalMidnight.format());
// e.g. - 2015-10-28T00:00:00-06:00
console.log(lastUTCMidnight.format());
// e.g. - 2015-10-29T00:00:00+00:00
console.log(lastLocalMidnight.unix());
// e.g. - 1446012000
console.log(lastUTCMidnight.unix());
// e.g. - 1446076800
$timezoneBeforeSet = date_default_timezone_get();
echo $timezoneBeforeSet."\n";
Notice how moment.js's format() function displays the UTC offset by default. So even printing in that way looks like the midnight you want, but you know it wouldn't end in 00:00:00 if you formatted it to be in UTC (or any timezone other than the one you requested the date in originally).
For the moment converted to UTC ahead of time, there is no offset. If you later formatted that one in your local timezone, it would not be at 00:00:00, and the output of moment.js format() would indicate a timezone offset based on the timezone you set (-06:00, for example).
3. On the PHP side of things, you have a default environmental timezone set, as we demonstrated by seeing what PHP thought of the unix timestamp "0". So, knowing a little more about what they represent now, let's take the unix timestamps we obtained from moment.js and try to format them with PHP's date.
// Timestamps obtained from moment.js
$unixTimestampLocalMidnight = 1446012000;
$unixTimestampUTCMidnight = 1446076800;
// Relative to untampered timezone set in your PHP environment
$phpLocalMidnightUnchangedTZ = date('Y-m-d H:i:s', $unixTimestampLocalMidnight);
echo $phpLocalMidnightUnchangedTZ."\n";
// 2015-10-27 23:00:00
$phpUTCMidnightUnchangedTZ = date('Y-m-d H:i:s', $unixTimestampUTCMidnight);
echo $phpUTCMidnightUnchangedTZ."\n";
// 2015-10-28 17:00:00
So yeah. Those are totally not what we were wanting, right? Actually they are. It's 23:00:00 somewhere and 17:00:00 somewhere when it's midnight somewhere else, right?
We need to be sure where PHP thinks we are right now. We could output that timezone information using Date, but we don't care to see it in our final output (understandable). So how do we find out, otherwise? Glad you asked:
$timezoneBeforeSet = date_default_timezone_get();
echo $timezoneBeforeSet."\n";
// US/Pacific
I'm in Colorado which is US/Mountain, so what's the deal? Well, this must mean the online PHP sandbox I was using is hosted over in California or something. Makes sense. Know where your code is running.
But don't get too caught up worrying about that. This is why we capture and convert to a consistent format upfront and worry about formatting only at which point we really need it. That way, if you did your conversion wrong, you only need to change it in one or two places at most.
For a complete reference to PHP timezones, click here.
4. If you have any control of your PHP environment, you should be setting the default timezone to UTC (one of the very first things you do in your project bootstrapping or in your PHP environmental config file).
// Explicitly set PHP default timezone to UTC
date_default_timezone_set('UTC');
$timezoneAfterSet = date_default_timezone_get();
echo $timezoneAfterSet."\n";
// UTC
$phpLocalMidnight = date('Y-m-d H:i:s', $unixTimestampLocalMidnight);
echo $phpLocalMidnight."\n";
// 2015-10-28 06:00:00
$phpUTCMidnight = date('Y-m-d H:i:s', $unixTimestampUTCMidnight);
echo $phpUTCMidnight."\n";
// 2015-10-29 00:00:00
So this makes sense. We are showing a time relative to UTC now. If I had originally captured a midnight in US/Mountain time, I would expect to see a time of day that corresponds to that over in Greenwich, England.
When you know a date is formatted with a timezone, think of reading that date-time in the place the timezone indicates. We know PHP is spitting out UTC stuff, so I can imagine I'm in Greenwich, England when I see the output.
If it's 06:00 in the morning and I am in Greenwich, it should be 6 hours earlier in Colorado (-6:00) <-- remember that useful timezone suffix moment.js outputs with .format()? The sun hasn't quite risen yet in Colorado because the sun rises in the East and sets in the West. So what time is 6 hours before 6AM? Midnight!
And of course the date we explicitly converted to UTC upfront comes back out looking like an actual midnight. Why? Because PHP is set to format dates in UTC. Also notice it's a day ahead. You should know enough now to explain that yourself =)
Make sense?
You have to create the date without the hour part first, something like this:
var moment = require("moment");
var unixTime = moment().startOf('day').unix(); //last midnight in local time
console.log("Your timestamp: " + unixTime + " And your date: " + day);
Now, let's see your examples.
Yo said that this unix timestamp 1446073200 but, you when you check here, you can see that this is the date that represents:
UTC: Wednesday 28th October 2015 11:00:00 PM
And also gives you another date with your local time, which in my case:
In your local time zone: Wednesday 28th October 2015 05:00:00 PM
So, my guess is that you are getting that unix timestamps in a place with timezone UTC + 1 and that's why you believe that this unix timestamp 1446073200 has no the hour part.
In my previous example you will get a unix timestamp in your local time, which in my case is: 1446098400, but you will probably want the UTC time, so you should change the code a little bit, like this:
var moment = require("moment");
var unixTime = moment.utc().startOf('day').unix(); //last midnight in UTC time
console.log("Your timestamp: " + unixTime + " And your date: " + day);
That will give you this unix timestamp: 1446076800which is the one you need. You can check it here.
UTC: Thursday 29th October 2015 12:00:00 AM
I simplified my code using #forgo answer.
This is how I do in pure Javascript:
var today = new Date()
today.setUTCHours(0, 0, 0, 0)
var today_timestamp = Math.floor(today.getTime() / 1000)
If you want to get the value for the current timezone, use setHours instead.

Categories