Difficulty converting json string to date format in d3 - javascript

I've tried to look at some code examples for this but I'm stuck here. I have a json which is reading dates as strings. For example:
1/1/1993 is 33970.
I have points on a map, each with associated dates. I have a time-slider based on dates. Once the time slider is updated, I would like the appearance of the points to change based on the date value of slider.
// build slider
var inputValue = null;
var year = ["1993","1994","1995","1996","1997","1998","1999","2000","2001","2002","2003","2004","2005","2006","2007","2008","2009", "2010","2011","2012","2013","2014","2015","2016","2017","2018","2019"];
Build function to update slider.
function update(value) {
document.getElementById("range").innerHTML=year[value];
inputValue = year[value];
d3.selectAll(".points")
.attr("fill", dateMatch);
}
d3.select("#timeslide").on("input", function() {
update(+this.value);
console.log(value)
});
And finally, build the function that matches the date in my data, to the date in the time slider!
function dateMatch(data, value) {
var d = new Date(data.properties.Sign_Date);
var y = [d.getFullYear()];
console.log(y)
console.log(d)
if (inputValue == y) {
this.parentElement.appendChild(this);
return "blue";
} else {
return "#999";
};
}
I think the template here should work but there is an issue reading in the dates in the dateMatch function. For some reason, it's just printing
Wed Dec 31 1969 16:00:41 GMT-0800 (Pacific Standard Time)
For every record in my data. Which doesn't make sense since my data doesnt even go back to 1969. Can anyone tell me what they think might breaking here, or better, an easier way to filter this temporal data?

You need to convert all your dates to real dates. Be aware, if you don't use UTC (universal time zone) or another defined timezone the date conversion will depend on the timezone set on the computer. For more about javascript dates I suggest reading MDN.
function createDateUTC(yourDateFormat) {
var parsed = yourDateFormat.split('/'),
day = +parsed[0],
monthIndex = +parsed[1]-1,
year = +parsed[2]
return new Date(Date.UTC(year, monthIndex, day))
}

Related

C# - TimeZone Issue in Asp.Net MVC

I am facing an issue in timezone. Right now I am saving time zone from client side and stored all DateTime in UTC. It's working properly but when I am trying to convert DateTime for UTC behind time zones like CST, EST, EDT it showing wrong data.
Issue -
Let's assume if I did any task at 10 PM EDT and it would be saved in DB as 2 AM(as per UTC) but when I am trying to fetch data for a day and passing current UTC date.
My question is If am trying to fetch data for a day like 11 midnight( from EST) to the current time, but my conversion from UTC to EST is wrong due to UTC 12midnight is yesterday's 8 PM(as EDT 4hr behind from UTC). (From Date[UTC convert to EDT] - 06/07/2017 08:00pm) and To Date - 06/07/2017 11:00 pm) Due to this conversion I am getting data from 8 pm to 11 pm only <- I am expecting from date is 06/07/2017 04:00 AM as per UTC.
Code -
Below is the code for conversion. In from date I have taken utcnow.date only and from a date
Javascript code -
function setTimezoneCookie() {
try {
var timezone_cookie = "timezoneoffset";
var timeZoneName = "timezonename"
var tz = jstz.determine();
var aa = tz.name();
// if the timezone cookie not exists create one.
if (!$.cookie(timezone_cookie)) {
// create a new cookie
$.cookie(timezone_cookie, new Date().getTimezoneOffset());
$.cookie(timeZoneName, aa);
}
else {
var storedOffset = parseInt($.cookie(timezone_cookie));
var currentOffset = new Date().getTimezoneOffset();
if (storedOffset !== currentOffset) {
$.cookie(timezone_cookie, new Date().getTimezoneOffset());
$.cookie(timeZoneName, aa);
location.reload();
}
else {
$.cookie(timeZoneName, aa);
}
}
}
c# code -
fromDate =Convert.ToDateTime(fromDate).ToClientTimeZoneinDateTime().ToString();
toDate = Convert.ToDateTime(toDate).ToClientTimeZoneinDateTime().ToString();
ObjectParameter totalRecords = new ObjectParameter("TotalRecords", typeof(int));
var DetailsList = objDetailsList.GetDetails(loginUserId,locationId, userId, taskType, pageIndex, numberOfRows, sortColumnName, sortOrderBy, textSearch, totalRecords, fromDate, toDate);
if (DetailsList.Count() > 0)
{
string output = BuildJQGridResults(DetailsList, numberOfRows, pageIndex, Convert.ToInt32(totalRecords.Value));
response.Write(output);
}
else
{
JQGridResults result = new JQGridResults();
List<JQGridRow> rows = new List<JQGridRow>();
result.rows = rows.ToArray();
result.page = 0;
result.total = 0;
result.records = 0;
response.Write(new JavaScriptSerializer().Serialize(result));
}
Below is the method of converting UTC time to client timezone
public static DateTime ToClientTimeZoneinDateTime(this DateTime dt)
{
try {
if (System.Web.HttpContext.Current.Request.Cookies["timezoneoffset"] != null || System.Web.HttpContext.Current.Request.Cookies["timezonename"] != null)
{
var timezonename = System.Web.HttpContext.Current.Request.Cookies["timezonename"].Value;
timezonename = timezonename.Replace("%2F", "/");
var timezoneLocal1 = FindTimezoneName(timezonename);
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(timezoneLocal1);
bool isCurrentlyDaylightSavings = tzi.IsDaylightSavingTime(dt);
if (isCurrentlyDaylightSavings == true)
dt.AddHours(1);
var timeOffSet = System.Web.HttpContext.Current.Request.Cookies["timezoneoffset"].Value;
var offset = int.Parse(timeOffSet.ToString());
dt = dt.AddMinutes(-1 * offset);
return dt;
}
return dt.ToLocalTime();
}
catch (Exception)
{
return DateTime.UtcNow;
}
}
No doubt as Timezone handled properly but facing an issue for behind timezone from UTC if end user trying to fetch data after 8 PM EDT. I have attached screenshot as well.
Below img of before conversion -
Above img of after conversion -
How do I need to handle this situation?
The main problem is that you're converting the wrong direction. You are converting from UTC to the user's time zone, but your input is in the user's time zone, so you need to convert the other direction - from the user's time zone to UTC. Then your query will show better results.
A few other things:
Don't convert time zones by trying to add/subtract minutes or hours manually. Use the conversion functions offered on TimeZoneInfo, such as ConvertTimeFromUtc, ConvertTimeToUtc, etc. There's no need to test for DST.
The try/catch shouldn't be in your code at all. Throw an exception if you can't perform the operation. Don't mask important errors by swallowing exceptions.
dt.ToLocalTime() shouldn't be in your code either. Never rely on the server's local time zone.
The offset returned by new Date().getTimezoneOffset() is the user's current offset. You cannot assume that it's the correct offset for the dates chosen. You don't that anyway, as you're already getting the time zone name. (You don't need the timezoneoffset cookie at all.)
The time zone name returned by jstz.determine() on the client-side is going to be an IANA tzdb identifier, such as America/Los_Angeles. These aren't going to work on the server-side with TimeZoneInfo.FindSystemTimeZoneById (unless you are running .NET Core on Linux or Mac). Conversion to a Windows time zone is required. I see you have a FindTimeZoneName function, which I assume is performing the conversion. You didn't show the details in your code, but I highly recommend you use my TimeZoneConverter library to implement that, as it's maintained with changes to time zones.
Reading cookies and time zone conversion are separate concerns. Don't bundle them together.
Ultimately, you should have something like this:
public static DateTime FromTimeZoneToUtc(this DateTime dt, string timeZone)
{
var windowsId = TimeZoneConverter.TZConvert.IanaToWindows(timeZone);
var tzi = TimeZoneInfo.FindSystemTimeZoneById(windowsId);
return TimeZoneInfo.ConvertTimeFromUtc(dt, tzi);
}
Or, even better, if you use Noda Time, then you don't need to convert time zones at all.
public static DateTime FromTimeZoneToUtc(this DateTime dt, string timeZone)
{
var tz = DateTimeZoneProviders.Tzdb[timeZone];
var local = LocalDateTime.FromDateTime(dt);
return local.InZoneLeniently(tz).ToDateTimeUtc();
}

how to disable moment.js daylight timezone conversion

It is possible to disable the daylight timezone conversion in moment.js?
http://plnkr.co/edit/MjFelt?p=preview
$scope.obj.date = moment('2016-06-03T04:00:00.000Z');
Basically my application deals with events and dates only, but moment.js converting the daylight savings time is causing issue with dates. Does it have any setting which will disable it across the entire application usage?
If you are saying that you want moment to display your date and time (which is UTC, as indicated by the 'Z'), exactly as is, you should use moment.utc:
moment.utc('2016-06-03T04:00:00.000Z').format()
"2016-06-03T04:00:00Z"
When you use the default moment constructor, as you are now, you are telling moment to convert your UTC time to local time, and this is why you are seeing a time difference. For instance, on my local machine (I am currently UTC-5) I get the following:
moment('2016-06-03T04:00:00.000Z').format()
"2016-06-02T23:00:00-05:00"
This question comes up quite a lot, so I wrote this blog post that explains moment's constructor functions and how it converts ISO8601 dates in detail: https://maggiepint.com/2016/05/14/moment-js-shows-the-wrong-date/
In my case, I had a problem with timezone changing due to 'daylight saving time'.
I had the next period:
{
"from": "2020-10-01 00:00:00 +0200",
"to":"2020-11-01 00:00:00 +0100",
}
And I wanted to get:
{
"from": "2020-10-01 00:00:00 +0200",
"to":"2020-11-01 00:00:00 +0200",
}
My solution is to get current (local) timezone and set it to the both date moment:
const currentTzOffset = moment().utcOffset(); // getting current timezone offset
const startToLocalZone = moment(from, yourDateFormat)
.local() // just checking. not sure if this is necessary
.utcOffset(currentTzOffset) // put your tz to here
.format(yourDateFormat);
const endToLocalZone = moment(to, yourDateFormat)
.local() // just checking. not sure if this is necessary
.utcOffset(currentTzOffset) // put your tz to here
.format(yourDateFormat);
console.log(startToLocalZone); // output: "2020-10-01 00:00:00 +0200"
console.log(endToLocalZone); // output: "2020-11-01 00:00:00 +0200"
And dont forget to set your date format instead 'yourDateFormat'
var tz = 'America/Vancouver'; // or whatever your time zone is
var dt = '2022-03-13T07:00:00.101Z'; // or whatever date/time you're working with
var momentVal = moment.tz(dt,tz)
function isNextDayDST(mObj){
return mObj.clone().add(1, 'days').isDST();
}
function isTodayDST(mObj) {
return mObj.clone().isDST();
}
function getDSTHourCompensation(mObj) {
const todayDST = isTodayDST(mObj.clone());
const tomorrowDST = isNextDayDST(mObj.clone());
if(todayDST == false && tomorrowDST == true) {
return 1
}
if(todayDST == true && tomorrowDST == false) {
return -1
}
return 0
}
function removeDST(mObj){
const hourCompentation = getDSTHourCompensation(mObj);
return mObj.clone().add(hourCompentation, 'hours');
}
console.log(momentVal.format('YYYY-MM-DD HH:mm'))
console.log(removeDST(momentVal).format('YYYY-MM-DD HH:mm'))
Maybe use the moment lib to compensate for the hours when you want to remove DST for the particular case.

d3.max return wrong date

I have a kind a weird problem. I'm loading data for a overview page. I need to show max date, so users know which time period they're dealing with. Now, I know which date this should be (today or yesterdays date, this is updated once a night) but I would like to do a max function anyway, in case something goes wrong during the update.
The problem I'm having is that both d3.max and a custom max-date function returns the wrong date. One month in the future, so today should show 7/9 2015 but instead it displays 7/10 2015. When I filter the data on 7/10 i get an empty array. In fiddle this works alright so there is something fishy going on. I do run an d3.tsv(tsv is right, even if the extension says .csv the file is in fact tab-separated), might be something there that's causing trouble? Any ideas where i might go wrong? The parsefunction alone returns the right results, the dates when read have the following format: dd.mm.yyyy
//Dateformatting
function parseDate (dateStr) {
var s1 = dateStr.split(" ");
var s1dat = s1[0].split(".");
return new Date(s1dat[2], s1dat[1], s1dat[0])
};
var dateArr = [];
//Occupation
d3.tsv("data.csv", function(error, data, tsv) {
datasetIn = data;
datasetIn.forEach(function(d) {
d.datum = parseDate(d.datum);
d.Patients = +d.Patients.replace(",", ".");
d.Beds= +d.Antal_vardplats.replace(",", ".");
});
for (index = 0; index < datasetIn.length; ++index) {
dateArr.push(datasetIn[index].datum);
}
var maxYear = d3.max(dateArr).getFullYear();
var maxDate = d3.max(dateArr);
})
In JavaScript month values are zero-based beginning with 0 for January to 11 for December. Passing in a human-readable 9 representing September to new Date() is supposed to create a Date object for October instead.
new Date("2015", "9", "7").toDateString(); // "Wed Oct 07 2015"
Adjusting for this should give you the correct result when parsing human-readable date values.

I know there must be an easier way to do this: Javascript function model returning a date

I have to say, I am not an expert with Javascript dates.. at all! I have looked at DateJS for instance, however my problem is not just a simple date conversion (or maybe it should be!).
Quick background:
I have a service call which returns some JSON data that include the dreaded Epoch style date from WCF/REST (I can't use Webapi at the moment - which would give me native JSON.NET?).
So a date examlple from the JSON object is:
StartDate: "/Date(1343378404560+0100)/"
Now, the JSON returned from my call has more information that I need for my Wijmo event calendar object, so I thought ok, will create a Javascript function/model for my Wijmo event object, and use jQuery MAP function to select only the fields I need.
My Javascript event model looks like this:
function wijmoEventModel(in_id, in_calendar, in_subject, in_location, in_start, in_end, in_description, in_colour, in_allday, in_tag) {
this._id = in_id;
this._calendar = in_calendar;
this._subject = in_subject;
this._location = in_location;
this._start = jsonDate(in_start);
this._end = jsonDate(in_end);
this._description = in_description;
this._colour = in_colour;
this._allday = in_allday;
this._tag = in_tag;
// Public Properties/Methods
return {
id: this.id,
calendar: this._calendar,
subject: this._subject,
location: this._location,
start: this._start,
end: this._end,
description: this._description,
color: this._colour,
allday: this._allday,
tag: this._tag
}
};
So, I have another little function that uses the jQuery MAP function as so:
function returnWijmoCalendarObject(diaryEventData) {
// Using jQuery map, reduce our raw event data down to only the required wijmo calendar items
var _calobj = $.map(diaryEventData, function (fld) {
return new wijmoEventModel(fld.ID, fld.ResourceCalendarID, fld.EventTitle, fld.Location, fld.StartDate, fld.EndDate, fld.Description, fld.ResourceColour, fld.AllDay);
});
return {
calendardata: _calobj
}
};
SO the above function just selects the required fields from my original full JSON return, and uses my Javascript function/model to return a new "calendardata" JSON object which I can use with my Wijmo event calendar..
There is one more small function which converts the Epoch style date "/Date(1343378404560+0100)/"
into (I think!) a real Javascript Date object.. like this:
function jsonDate(rawDate) {
var d = new Date();
d.setMilliseconds = parseInt(rawDate.substr(6));
return d;
}
So the above little function of course is used in the first code block above to hopefully convert that Epoch style original date into a Javascript Date.
SO MY QUESTION/PROBLEM IS:
The model above, and jQuery map function works well, I get a subset JSON object of exactly the structure I need, however the dates returned (wijmoEventModel.start & end) don't come back as a Javascript Date object?? even though debuging in that wijmoEventModel definitely has the dates as JS date objects??
Obviously I am missing/not understanding some vital and fundamental aspects here!!!
PLEASE! if anyone can help as this is driving me crazy...
David.
In the jsonDate function, the setMilliseconds property of d (not d itself) will be a date, which you could call from wijmoEventModel.start.d. You actually want var d = new Date(parseInt(rawDate.substr(6))). (Or do you want var d = new Date(parseInt(rawDate.split('+')[0]))?)
Setting milliseconds only sets the milliseconds part of a date, it doesn't set the date from an epoch.
At the heart of a javascript date object is a number of milliseconds since 1970-01-01 00:00:00 in UTC. So if the "time since epoch" that you have is the same, if you convert it to a number you can do:
var d = new Date( Number(millisecondsSinceEpoch) );
See ECMA-262 15.9.3.2
This will create a date object in the local timezone based on the "time since epoch" in UTC. So in different time zones it will show a different time that represent the same instant in UTC.
e.g.
var millisecondsSinceEpoch = '1343378404560';
alert( new Date(Number(millisecondsSinceEpoch))); //Fri Jul 27 2012 18:40:04 GMT+1000 (EST)
The time in the OP is '1343378404560+0100' which implies an offset that I'll assume is hhmm. So that needs to be subtracted from the number before passing it to Date:
var s = '1343378404560+0100';
var t = s.split('+')[1];
if (t) {
t = t.substring(0,2)*3600 + t.substring(2)*60;
} else {
t = 0;
}
var d = new Date(parseInt(s) - t * 1000); // Fri Jul 27 2012 17:40:04 GMT+1000 (EST)
Edit
The above assumes a sign of "+", the string should be split on either "+" or "-", then the sign detected and applied later, e.g.
var t = s.split(/[-+]/)[1];
After setting the value of t, apply the sign:
t *= /-/.test(s)? -1000 : 1000;
var d = new Date(parseInt(s) - t);
Or some variation of the above.

javascript: How to hide DIVs/ULs that represent past dates?

I have some code that looks like this:
<h3>Thursday Sep 10</h3>
<ul>great stuff in here</ul>
<h3>Friday Sep 18</h3>
<ul>other stuff in here</ul>
They have a basic jQuery hidey-showy thing happening: click on the H3, and the UL underneath expands or contracts. By default they are all showing/open.
I'd like to set it up so that any date that has passed (like Sep 10 in this example) is contracted by default.
I don't seem to be able to get my CMS to spit out a nice compare-able date (like epoch time) to use as an ID for the H3. Is there a way I can use js's Date() function to build something like that out of the existing information ("Thursday Sep 10"), or some other way entirely to get this done?
(All of the dates are in 2009 and the site won't exist in 2010, so hardcoding the year into any functions is A-OK if that's what needs to be done.)
Thanks!
The first hurdle is to convert your text dates into valid strings that can initialize JavaScript date objects.
The conversion process (including valid string formats) is covered on http://programming.top54u.com/post/Javascript-Convert-String-to-Date.aspx.
Unfortunately, your text representations are not valid inputs for the JavaScript Date constructor. You will need to write a function to convert your strings into a valid representation before using them in the Date constructor.
Once you have your Date objects initialized, you can compare them (see "Compare Two Dates" on http://www.w3schools.com/jS/js_obj_date.asp).
I agree with Mayo. If you had access to the date time value and wanted to convert it to a string similar to what you have ("Thursday Sep 10"), you could use this.
Keep it simple; you don't really need a proper date parser to compare your dates. I've got the feeling that you're looking for something quick and dirty:
var now = new Date();
var nowHash = now.getMonth() << 5 + now.getDate();
$("h3").each(function (e) {
var tokens = $(e).html().split(" ");
var hash = [ "Jan", "Feb", ..., "Dec" ].indexOf(tokens[1]) << 5 + tokens[2];
if (hash < nowHash) {
// contract the <ul> that follows
}
});
Month * 32 (or shift 5 bits to left) + day is enough to give you a unique hash of a date that can be compared with other dates.
Mayo is correct about having no quick way. So here is my take on DIY solution.
Basically you extract the date and compare the date yourself.
var aMonths = { "Jan":0, "Feb":1 ..., "Sep":8, ... };
var aToday = new Date();
var aH3Text = .....; // Get the value via jQuery
var aDataElements = aH3Text.split("");
var aMonthIndex = aMonths[aDataElements[1]];
var aDateIndex = aDataElements[2];
var aH3Date = new Date();
aH3Date.setFullYear(2009, aMonthIndex, aDateIndex);
if (aH3Date > today) {
// BEFORE today
} else {
// AFTER today
}
Hope this helps.

Categories