I am using the Moment.js library and I am trying to get the number minutes that have passed since midnight for a given timestamp. It works well, except for on days in which day light savings occurs (etc. March 8th, 2015).
How can i accurately get the number of minutes since midnight for all days of the year? Do I have to get the timezone or offset?
http://jsfiddle.net/0uvz61xo/1/
Javascript
$(document).ready(function () {
var minutesFromMidnight = moment("2015-03-08 03:05:00").diff(moment("2015-03-08").startOf('day'), 'minutes')
$('#minutes').text(minutesFromMidnight);
});
HTML
Actual Minutes: <div id="minutes" style="font-weight: bold; color: red;"></div>
<br />
Expected Minutes: <b>185</b> (3 hours and 5 minutes after midnight)
The code you gave is indeed the correct way to get the number of elapsed minutes since the start of the day, and the results are correct. Even though the time on the clock is 3:05, there have actually only been 2 hours and 5 minutes elapsed since midnight, since the hour between 2:00 and 3:00 was skipped. In the fall, you'd have the opposite effect - that an extra hour is added, as the hour between 1:00 and 2:00 is repeated.
It's important to realize that DST is not the same for everyone. Many countries don't have it at all, and those that do have it don't all do it on the same days or at the same time of day. For example, Brazil springs forward in October and skips the hour from 00:00 to 01:00. So on that day midnight doesn't exist. The start of day is 1:00 on that day. Hopefully that helps you understand why time elapsed since midnight is not necessarily equivalent to the hours and minutes values on the clock. If midnight doesn't exist the question is invalid, and even if it does exist that doesn't account for possible discontinuities.
That said, if you really need a time-of-day value as a raw number of minutes, it's quite easy to get that:
var m = moment("2015-03-08 03:05:00");
var result = m.hour() * 60 + m.minute();
Though do keep in mind that this is not elapsed time since midnight.
Also recognize that if you have a value like 2015-11-01 01:30:00 in the US, that's during the fall-back transition so there are two instances of 1:30. First comes 1:30 daylight time, then an hour later comes 1:30 standard time. You can calculate 90 as the result of this time, but that in no way tells you which of the two instances it was. Again, it's not necessarily 90 minutes since midnight. It could be, or it could be 150 minutes since midnight if it was the second occurrence of 1:30 AM.
See also, the DST tag wiki, which has some nice graphs to help you visualize this.
Related
The proposed JavaScript Temporal date/time API casually mentions “Interpreting years, months, or weeks requires a reference point” (source), but I fail to understand what is meant by this.
More specifically, the following is not possible:
let oneWeek = Temporal.Duration.from({ weeks: 1 });
console.log(`one week is ${oneWeek.total('day')} days`);
It will result in the following error:
RangeError: a starting point is required for balancing calendar units
This can be resolved by bloating my code with a relativeTo parameter to the total() call, as follows:
console.log(`one week is ${oneWeek.total({ unit: 'day', relativeTo: Temporal.Now.plainDateISO() })} days`);
But could anyone elaborate on why this is necessary? As far as I can tell a week has always been and will always be seven days…?
As far as I can tell a week has always been and will always be seven days
Even around a daylight saving time change?
You know, those Sundays where you change the clock back or forward by one hour?
If you measure a duration from, say, Wednesday to the next Wednesday, then this “one week” could be exactly 7 days long, or 6 days and 23 hours, or 7 days and 1 hour.
See the documentation on Balancing Relative to a Reference Point:
Balancing that includes days, weeks, months, and years is more complicated because those units can be different lengths.
In the default ISO calendar, a year can be 365 or 366 days, and a month can be 28, 29, 30, or 31 days.
In other calendars, years aren’t always 12 months long and weeks aren’t always 7 days.
Finally, in time zones that use Daylight Saving Time (DST) days are not always 24 hours long.
This is also referring to leap years.
There’s also discussion in issue #857:
Specifically, the following time scale unit conversions are contextual (the “conversion boundaries”):
year ↔ day (365, 366 days)
month ↔ day (28, 29, 30, 31 days)
minute ↔ second (59, 60, 61 seconds)
That last one is referring to leap seconds.
And of course, the Temporal API has to account for what happened in September, 1752.
Related: Get number of days in a specific month that are in a date range.
The point is that the answer to the question of how long some unit of time is, will change depending on context.
This isn’t just about time zones; different calendars have all sorts of anomalies.
Sure, the proleptic Gregorian calendar used in browsers might not be affected by the year 1752, but that requires knowledge about which calendar to use.
You supply this information with relativeTo; it’s contained within Temporal.Now.plainDateISO().
Now it’s clear that an ISO week can be used which will always have 7 days.
But without this information, it’s impossible to tell exactly, and a general date and time API cannot be sure that an ISO week is what you actually meant.
I want to get how far away is the next occurence of a particular PST time regardless of the client's timezone.
This would be trivial if the time were in UTC but I don't know how to do it in PST keeping in mind the observance of daylight savings time.
Eg. 4 PM PST would be 11 PM UTC since it is right now summer.
I would prefer not to have to manually input the dates of daylight saving time.
I am happy to use a library if this is not possible without one.
// returns the number of milliseconds from the current time until the specified time in PST.
function getTimeUntil (hour, minutes = 0, seconds = 0)
{
// implementation needed
}
The following is an explanation of why this is likely a duplicate of How to initialize a JavaScript Date to a particular time zone.
PST (presumably US Pacific Standard Time) is a timezone with a fixed offset, UTC -8. Places that observe PST and have daylight saving typically call that offset Pacific Daylight Time (PDT), which is UTC -7.
PST might also be Pitcairn Standard Time, which is also UTC -8 and observed all year round on Pitcairn Island. Converting PST to UTC is achieved by adding 8 hours.
However, likely you want to work with times and dates for a place that observes US PST in winter and US PDT in summer, e.g. Los Angeles. In that case you can use a library like Luxon or date.js that allows creating dates based on a timestamp and specified IANA representative location such as "America/Los_Angeles". If that is the case, then see the link above.
My implementation:
// returns the formatted time from the current time until the specified time in PST.
function getTimeUntil (hour, minutes = 0, seconds = 0)
{
let future = luxon.DateTime.now().setZone('America/Vancouver').set({
hours: hour,
minutes: minutes,
seconds: seconds
});
let now = luxon.DateTime.now().setZone('America/Vancouver');
if (future < now)
{
future = future.plus({ days:1 });
}
return future.diff(now, ["hours", "minutes", "seconds"]);
// implementation needed
}
console.log(getTimeUntil(13, 0, 0).toObject());
<script src="https://cdn.jsdelivr.net/npm/luxon#2.0.1/build/global/luxon.min.js"></script>
Can anyone tell me how to convert minutes to hours using moment.js and display in hh:mm A format.
For example,
If minutes is 480 it should display output as 08:00 AM.
If minutes is 1080 it should display output as 06:00 PM
Assuming that you always want to add minutes from midnight, the easiest thing to do is:
moment.utc().startOf('day').add(480, 'minutes').format('hh:mm A')
The use of UTC avoids issues with daylight saving time transitions that would cause the time to vary based on the day in question.
If you actually want the number of minutes after midnight on a given day, including the DST transitions take out the utc and just use:
moment().startOf('day').add(480, 'minutes').format('hh:mm A')
Note that the accepted answer has potential issues with DST transitions. For instance if you are in a part of the United States that observes DST:
moment('2016-03-13').hours(2).minutes(30).format('hh:mm A')
"03:30 AM"
The result is not as expected, and will vary between going back and hour or going forward an hour depending on the browser.
Edit: Original answer has been updated to fix bug. As an additional comment, I would be extremely leery of any code that attempts to map a number of minutes to civil time. The bottom line is that 480 minutes into the day is not always 8:00 AM. Consider this in the context of your problem. DST bugs are likely right now.
You can just do the basic arithmetic like so:
function getTimeFromMins(mins) {
// do not include the first validation check if you want, for example,
// getTimeFromMins(1530) to equal getTimeFromMins(90) (i.e. mins rollover)
if (mins >= 24 * 60 || mins < 0) {
throw new RangeError("Valid input should be greater than or equal to 0 and less than 1440.");
}
var h = mins / 60 | 0,
m = mins % 60 | 0;
return moment.utc().hours(h).minutes(m).format("hh:mm A");
}
getTimeFromMins(480); // returns "08:00 AM"
getTimeFromMins(520); // returns "08:40 AM"
getTimeFromMins(1080); // returns "06:00 PM"
I'm looking for best practices regarding dates - where it's the date itself that's important rather than a particular time on that day.
An excellent start was this question:
Daylight saving time and time zone best practices
I'd like some guidance applying this for my situation. I have medications starting on a particular date, and ending on another. I then need to query medications which are active in a given date range.
I've tried setting start and end dates as midnight local time, then storing in UTC on the database. I could add timezone entries too.
I'm using moment.js on both client and server, and can use moment timezone if needed.
I'm wondering how to deal with the effect of DST on my times - which makes an hour difference in my locally-midnight UTC times between DST and non DST periods.
The problem I have is for example when some medications have end dates set during a DST period, and some which were set in a non-DST period. Then, their UTC times differ by an hour. When a query is made for a particular date range starting at local midnight, it's not accurate as there are two different representations of midnight. The query itself may treat midnight as one of two different times, depending on when in the year the query is made.
The end result is that a medication may appear to end a day later than it should, or start a day earlier.
A simple but wonky workaround would be to consistently set the start date as 1am in standard (non DST) time, and end dates as 11:59pm standard (non DST) time, and query at midnight.
Or, should I check the start and end dates of each query, and work out what the UTC offset would be for each date?
But I'd much prefer to know what best practice is in this situation. Thanks.
Both the JavaScript Date object and the moment object in moment.js are for representing a specific instant in time. In other words, a date and a time. They internally track time by counting the number of milliseconds that have elapsed since the Unix Epoch (Midnight, Jan 1st 1970 UTC) - ignoring leap seconds.
That means, fundamentally, they are not the best way to work with whole calendar dates. When you have only a date, and you use a date+time value to track it, then you are arbitrarily assigning a time of day to represent the entire day. Usually, this is midnight - but as you pointed out, that leads to problems with daylight saving time.
Consider that in some parts of the world (such as Brazil) the transition occurs right at midnight - that is, in the spring, the clocks jump from 11:59:59 to 01:00:00. If you specify midnight on that date, the browser will either jump forward or jump backward (depending on which browser you are using)!
And if you convert a local date-at-midnight to a different time zone (such as UTC), you could change the date itself! If you must use a date+time to store a date-only value, use noon instead of midnight. This will mitigate most (but not all) of the adjustment issues.
The better idea is to treat whole dates as whole dates. Don't assign them a time, and don't try to adjust them to UTC. Don't use a Date or a moment. Instead, store them either as an ISO-8601 formatted string like "2014-11-25", or if you need to do math on them, consider storing them as an integer number of whole days since some starting value. For example, using the same Jan 1st 1970 epoch date, we can represent November 11th 2014 as 16399 with the following JavaScript:
function dateToValue(year, month, day) {
return Date.UTC(year, month-1, day) / 86400000;
}
function valueToDate(value) {
var d = new Date(86400000 * value);
return { year : d.getUTCFullYear(),
month : d.getUTCMonth() + 1,
day : d.getUTCDate()
};
}
There are a few other things to keep in mind when working with whole dates:
When working with ranges of whole dates, humans tend to use fully-inclusive intervals. For example, Jan 1st to Jan 2nd would be two days. This is different from date+time (and time-only) ranges, in which humans tend to use half-open intervals. For example, 1:00 to 2:00 would be one hour.
Due to time zones, everyone's concept of "today" is different around the globe. We usually define "today" by our own local time zone. So normally:
var d = new Date();
var today = { year : d.getFullYear(),
month : d.getMonth() + 1,
day : d.getDate()
};
You usually don't want to shift this to UTC or another time zone, unless your business operates globally under that time zone. This is rare, but it does occur. (Example, StackOverflow uses UTC days for its calculations of badges and other achievements.)
I hope this gets you started. You asked a fairly broad question, so I tried to answer in way that would address the primary concerns. If you have something more specific, please update your question and I'll try to respond.
If you would like even more information on this subject, I encourage you to watch my Pluralsight course, Date and Time Fundamentals.
I need the epoch time in days. I've seen posts on how to translate it to date but none in days. I'm pretty bad with epoch time...how could I get this?
I need the epoch time in days
I'll interpret that you want the number of days since the epoch. The epoch itself is day zero (or the start of day 1, however you want to view it).
At the heart of a javascript Date object is a number of milliseconds since 1970-01-01T00:00:00Z. So to get the number of days from then to now you simply get the current time value and divide it by the number of milliseconds in one day:
var now = new Date();
var fullDaysSinceEpoch = Math.floor(now/8.64e7);
For 2012-10-05 you should get 15618. Not sure if it allows for leap seconds and such, but it should be close enough (within a few seconds) if the system clock is accurate.
It is only when reading values of a Date object (such as getHours() and toString()) that the timezone offset is applied to give local times.