Approximating dates - Javascript/JSON - javascript

I'm trying to visualize some data I have. Here is the fiddle: http://jsfiddle.net/hohenheim/6R7mu/10/
For this visualization, I started a small subset of the JSON data I'm trying to visualize, data2 which looks like
data2 = [
{
"startDate":1396263600.0,
"adId":2483231759355,
"endDate":1401101940.0,
"impressions":754831
},
{
"startDate":1393851600.0,
"adId":2750329551133,
"endDate":1404212340.0,
"impressions":3947368
}
];
Notice there is a date range in the data. My goal is to split the impressions uniformly into all the days in that date range and aggregate all the impressions per day over all ads. IE the final result will only have 2 attributes: date and impressions. I have a solution that SHOULD work but days are not aggregating properly because the millisecond representations of the days are not equal even though they may approximate to the same day. For example, 1398164400000 and 1398171600000 represent the same day but have different millisecond values.
Basically, if you examine the middle part of the region on the chart, notice there are oscillating values but really each pair of differing values should actually represent just 1 day summed together.
Is there any way to properly merge 2 millisecond versions of dates that approximate to the same day?

Most clocks that are used to produce timestamps don't include leap-seconds, so you can isolate the day part by subtracting
(t % (24 /* hours per day */
* 3600 /* seconds per hour */
* 1000 /* milliseconds per second */ ))
from the time-stamp t.
Even if the timestamp does include leap-seconds, that function will still give you a pretty good proxy for day-of comparison. It just may get dodgy with timestamps that are close to midnight.
If you are in a time-zone that is far from the day boundary, you will probably want to adjust your timestamp to millis since the epoch in the local timezone, and just ignore DST which again will introduce some inaccuracy around midnight.

Related

Unknown date format /Date(1427982649000-0400)/

I need to display on the screen some date values but I'm receiving them in a format that I don't know. Does anybody know what format is this and how to convert them?
For example, I'm getting this:
/Date(1427982649000-0400)/
In the database is stored as
2015-04-02 09:50:49.000
I really don't know where to start looking at.
It's a unix timestamp in milliseconds, followed by a timezone (shift in hours differing from UTC).
So, it's UTC -4 hours, 1427982649 seconds after the 1st January of 1970.
Nice little tool for checking unix timestamps : http://www.unixtimestamp.com/index.php (don't forget to convert your milliseconds to seconds before posting them there)
/edit: To add some additional information - the "timezone shift" seems to be following RFC822 (and/or probably some other RFCs), that -0400 can be explained by the syntax "+/-HHMM" specified there, so to be exact it means -04 hours, 00 minutes.
The actual time and date gets converted into the milliseconds, and it follows the Unix time January 1st, 1970.
Because it is the date when the time for the Unix computer started.
But you can convert the milliseconds into the actual time by using some loops or conversions according to that time.
Does anybody know what format is this and how to convert them?
It seems that "/Date(1427982649000-0400)/" is a time value in milliseconds followed by an offset as ±HHmm. To convert that to a Date, use the time value adjusted by the offset.
Assuming the offset uses the typical sign convention, then a positive offset needs to be subtracted and negative offset added to get the correct UTC value, then something like the following should suit:
var s = '/Date(1427982649000-0400)/';
// Get the number parts
var b = s.match(/\d+/g);
// Get the sign of the offset
var sign = /-/.test(s)? -1 : +1;
// Adjust the time value by the offset converted to milliseconds
// and use to create a Date
var ms = +b[0] + sign * (b[1].slice(0,2)*3.6e6 + b[1].slice(-2)*6e4);
console.log(new Date(ms).toISOString()); // 2015-04-02T17:50:49.000Z
In your example, "2015-04-02 09:50:49.000" does not have a timezone, so it represents a different moment in time for each timezone with a different offset. If that is the actual value stored in the database, then I guess the missing timezone is UTC-0800. It is much better to store the values using UTC and to include the offset, then the host timezone is irrelevant.
Things are complicated here because ECMAScript timezone offsets are the opposite sign to the normal convention, i.e. positive for west of Greenwich and negative for east. If that convention is applied, then "/Date(1427982649000-0400)/" converts to 2015-04-02T09:50:49.000Z, which may be what you're after.
If that is the case, just change the sign in the line:
var sign = /-/.test(s)? -1 : +1;
to
var sign = /-/.test(s)? +1 : -1;

Date ranges with DST in javascript

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.

Why moment.utc(...).diff(moment.utc(...)) gets affected by source date offsets

Check the following code sample:
moment.utc("2014-10-19T09:27:57.9417128+00:00")
.diff(moment.utc("2014-10-19T09:27:57.9417128+02:00"))
I would expect 0 since I'm converting both dates to UTC, but this gives 7200000 as result.
In fact, I'm looking to get moment.fromNow or moment.from to work with UTC in order to get a X seconds/minutes/hours... ago without an invalid result because of Date/moment translating date-times based on the date's offset.
What am I doing wrong here?
I'm not sure why you would think the source offsets should be ignored. They are especially relevant for converting to UTC, because they actually represent the difference between UTC and the time represented.
In the first timestamp, the +00:00 means the time is already at UTC. In the second timestamp, the +02:00 means the time is two hours ahead of UTC. 2 * 60 * 60 * 1000 = 7200000.
In other words:
2014-10-19T09:27:57.9417128+00:00 == 2014-10-19T09:27:57.9417128Z
- 2014-10-19T09:27:57.9417128+02:00 == 2014-10-19T07:27:57.9417128Z
=======================================================================
02:00:00
There is no way the result should be zero, because any way you look at it, the two timestamps represent two different moments in time that are separated by two hours.
Since moment's fromNow function already works with the current UTC time, and you have a full ISO timestamp with an offset, you can just use it directly without any conversion.
moment("2014-10-19T09:27:57.9417128+02:00").fromNow()
You don't even need to convert to UTC first. You could do it like this:
moment.utc("2014-10-19T09:27:57.9417128+02:00").fromNow()
But these will both return the same thing because you have already supplied the offset. They would only differ if you didn't include an offset, in which case the first example would interpret the input string in local time and the second case would interpret the input string in UTC. Neither of which change the behavior of the fromNow function.

DC.js X-axis hour labels appear as thousandths

Using dc.js to build some charts. The localHour attribute contains numbers between 0 and 23. However, when using this on my axis, all numbers are reported as thousandths instead of the standard hour. 04 PM also appears at the origin.
How can I fix this?
var hourDim = ndx.dimension(function(d){ return d.hour; });
var num = hourDim.group().reduceSum(dc.pluck('count'));
var mainChart = dc.lineChart("#main");
mainChart
.width(500).height(200)
.dimension(hourDim)
.group(num)
.x(d3.time.scale().domain([0,24]))
.yAxisLabel("Count per Hour")
What's actually going on here is that your "hour" measurements are being interpretted as milliseconds. Milliseconds are the default Javascript time unit if you don't specify otherwise. Specifically, you're getting milliseconds after the Javascript zero time, which is sometime on Dec 31 1969 or Jan 1 1970 depending on timezone adjustment, and apparently starts at 4pm in your timezone. The rest is just default formatting trying to make things look nice.
Unless you're doing other things that require the hours to be treated as timestamps, it is probably easiest to leave the hours as plain numbers, using a linear scale instead of a time scale.
If you're fine with plain old "1", "2", "3" on the axis labels, that's all you have to do.
If you want those numbers to look like hours, you need to set a tickFormat function on the chart axis.
You could just do something like
mainChart.x(d3.scale.linear().domain([0,24])
.tickFormat(function(h){return h + ":00";})
);
But that causes problems if the axis decides to put ticks at fractional values -- you'll get something that looks like 1.5:00 instead of 1:30. You could fix that with some math and number formatting functions, but at that point you're doing enough work to make it worth using proper date-time formatting.
To get proper hour:minute axis labels, you can use a d3 time formatting function to specify the format, but you're also going to have to translate the number of hours into a valid date-time object.
var msPerHour = 1000*60*60;
var timeFormat = d3.time.format.utc("%H:%M");
mainChart.x(d3.scale.linear().domain([0,24])
.tickFormat(function(h){
return timeFormat(new Date(msPerHour*h) );
})
);
Note that I've specified the time format function to use UTC time instead of local time, so that it treats zero as midnight. It still thinks it's midnight, Jan 1 1970, but you're also specifying the formatting to only include hours and minutes so that shouldn't be an issue.

Monotonic/Vixie-style DST interpretation in JavaScript

I'm looking for an JavaScript algorithm to convert local calendar date-times into UTC milliseconds since Unix epoch (or to Date objects representing the same). A typical, and often useful, way to do this for some relative calendar date YYYY-MM-DD hh:mm:ss.zzz is:
# Close, but not quite monotonic
(new Date(YYYY, MM-1, DD, hh, mm, ss, zzz)).getTime()
JavaScript implementations have their ways of dealing with DST (read: daylight saving time, summer time, your own locale's equivalent as necessary), and unfortunately they don't work for the application at hand, which instead calls for local time that is monotonic (but may be distorted if necessary).
The conversion must be monotonic in the sense that for two relative calendar dates (i.e. timezone-ignorant, DST-ignorant) A and B, the conversion, a function C, is such that
If A is strictly earlier than B then C(A) ≤ C(B)
If A is simultaneous to B then C(A) = C(B)
If A is strictly later than B then C(A) ≥ C(B)
(This doesn't refer to monotonicity in the sense that successive calls to a time-getting function are strictly non-decreasing—this application has no concept of the current time and doesn't need anything like that.)
I've started working on an implementation of my own, but it's threatening to be complicated, and I think perhaps someone else has better ideas.
The questions are:
Has this already been implemented?
If not, is there a saner way to implement this than what I've outlined below?
Do the discontinuity-finding heuristics work for all known DSTs worldwide?
JavaScript Date's behavior
The following represent the corner cases for DST in the US in 2012. The values are experimental results from Firefox. Here, let the function C represent the result of creating a Date object using the given local date and time, then using the getTime() method to retrieve the UTC milliseconds.
Skipped hour: On 2012-03-11, the start date of DST, the hour starting 02:00 is skipped in local time: The minute following 01:59 is 03:00. In Firefox, a later input time may result in an earlier resolved time; e.g. 01:45 < 02:15, but C(01:45) > C(02:15), so the scale is not monotonic.
Doubled hour: On 2012-11-04, the end date of DST, the hour starting 01:00 occurs twice in local time: The minute following 01:59 daylight time is 01:00 standard time, then the minute following 01:59 standard time is 02:00 standard time. In Firefox, C(01:30) corresponds to the later repetition, 01:30 standard time.
This does not break monotonicity, as long as the resolving behavior is guaranteed to favor the later time. (I don't have documentation of this guarantee, but perhaps it follows from some language in ECMA-262.)
Required/preferred behavior
Here, let the function C represent a conversion with the desired behavior.
Skipped hour: The date for a skipped minute should be resolved to the first following unskipped minute. For example, on the DST start date, 02:15, 02:30, and 02:45 would resolve to the next unskipped minute, 03:00; in other words, C(02:15) = C(02:30) = C(02:45) = C(03:00).
Unskipped times would remain untransformed: Compare 01:45 < 02:15 < 02:45 < 03:15 to C(01:45) < C(02:15) = C(02:45) < C(03:15).
Doubled hour: The date for a minute occurring multiple times should be resolved to the first occurrence only; e.g. 01:30 on the end date of DST would be resolved to 01:30 daylight time rather than standard time, since that is the earlier of the two.
Same as before, except that the earlier time is guaranteed.
These rules are loosely based on those of Vixie cron. However, this application doesn't deal with a concept of current time and thus doesn't have the state it would need to watch the clock for time changes. It would need some other way to determine if and when times will be skipped or doubled.
Incidentally, as an additional requirement, the implementation must not assume that it is running in a US locale; it needs to work internationally and, wherever possible, use detection over configuration.
Implementation thoughts
One thing I thought might work for detecting whether a date falls into a discontinuity would be to test the width of the span of the local dates ±1 calendar day from the date. If the difference between the UTC times of the two dates is less than or greater than 48 hours, it would imply that some time had been skipped or doubled, respectively.
If skipped, we might further determine whether the given time itself is skipped if, after converting to UTC and back, the hh:mm:ss.zzz reads differently. If so, the time is resolved to the first minute after the discontinuity.
If doubled, we might determine the range of all times in the later repetition. If the given time falls within the later repetition, it is reverted to the earlier; otherwise, it is left alone.
Both of these could require the exact location of the discontinuities, which could for example be accomplished with a binary search bounded by the ±1 dates.
This heuristic could fail for multiple reasons; though I'm of the impression that they are unlikely, summer time rules are strange and inconsistent worldwide:
If it's possible for more than one discontinuity in either direction to occur within the same 3 calendar days. (In the US, there are two per year, months apart. I doubt anyplace adjusts any amount greater than, say, four hours.)
If the discontinuities are complementary, they may not be detected in the first place.
In any case, a simple search would make the assumption that there is only one discontinuity within the range.
If it's possible for a single discontinuity to account for a duration of (nearly) 3 calendar days. (In the US, each discontinuity accounts for one hour. I'm fairly certain that summer time adjustment is never on the order of days anywhere.)
An implementation consistent with Required/preferred behavior above, at least for the current USA rules, is now available. Overall, the mechanism isn't terribly inefficient. In the worst case (a skipped minute), it's O(lg n) where n is the number of minutes of change between summer and winter (60 where I live), and in all other cases, it's O(1).
The input is a "face" (a calendar date and time ignorant of DST).
The output is a Date with its local face set based on the input face.
If the input face represents exactly one local date, the output Date is the same as if the stats of the face were passed to the Date constructor.
If the input face represents zero local dates (due to DST skipping forward), the output Date reflects the first minute following the skip.
If the input face represents two local dates (due to DST repeating), the output Date reflects the earlier of the two.
Notes on the implementation:
The .getTimezoneOffset() method is used to determine whether two dates are on opposite sides of a discontinuity.
The offset before any discontinuity a face might be near is found by retrieving the offset of a Date 24 local hours prior to that face.
The face is converted to a Date by passing its stats to the Date constructor to be interpreted locally.
If the local face of the converted Date is not the same as the input face, this face is not directly representable in local time; it has been skipped.
The converted Date is treated as invalid.
The timezone offset following the discontinuity is determined by retrieving the offset of a Date 24 local face hours after the input face.
The difference between the offsets before and after the discontinuity is found. From that amount of time before the input face to that amount of time after (which should by definition both be representable as local dates), a binary search is used to locate the first minute after the discontinuity. A Date representing this minute is the output.
If the local face of the converted Date is the same as the input face,
If the converted Date has the pre-discontinuity offset, it is correct.
This includes any face not near a DST change; if there is no discontinuity, then all times for that day share the same offset.
Even if the face is in a doubled time, the early interpretation is the correct one. (Whether this can happen may be implementation-dependent.)
If the converted Date occurs after the discontinuity,
It is correct if it is at a time later than the discontinuity by at least the offset difference.
If it is in the range of time from the discontinuity through one offset difference afterward, it is in the later interpretation of a doubled time. The correct date is found by subtracting the offset difference, yielding the earlier interpretation.
A Date is determined to be in this range if a Date that is earlier by one offset difference has the early offset. Since the converted Date has the late offset, it is determined that the discontinuity happened more recently than that.

Categories

Resources