Converting to localtime at client with c# - javascript

I have a database with records stored in UTC. The c# .NET application reads the data and populates a *.cshtml table server-side. The server doesn't know the client's timezone as it is not a parameter reported by the browser, and there is no login or user form for the user to enter a profile and declare their timezone. The result is a table displayed in UTC at the browser.
I am aware that if the value is in a javascript variable then it is trivial to get the browser to make timezone offset adjustment. However, the data reaches the browser as a set of TD tags with text between.
Any solution I can think of to convert this to local time is inelegant - using javascript to walk through the table, get the innerHTML, parse it, adjust it, and put it back. That feels like an awful solution. Is there a better way? Pass the data as a JSON object and dynamically create the table via javascript? again it feels unwieldy. Is there a simpler way to make the browser take the values between the TD> tags and adjust, like
<TD> onsomething="this.innerHTML=adjustTime("2017-06-17 09:00:00");> </TD>
or a better way?

A general rule when dealing with times in different zones is to store & transmit the value in UTC and then allow the 'view' to display it as appropriate i.e. in the users current timezone.
I would add an API that provides a list of times in UTC, then allow the javascript client to render and display them as appropriate

Related

How can I prevent timezone localization in a Query object in the ArcGIS API for JavaScript?

I'm using the ArcGIS API for JavaScript (v3.28) to query hosted feature layers from a geodatabase. The API provides a Query class, in which the query itself and any configuration or parameters are defined, and a QueryTask class, that handles the actual execution of the query and returning the result set.
My problem is that when I query date-time information from these layers using the Query and QueryTask classes, the times returned are being incorrectly assigned a timezone, and are also improperly localized. This is likely a result of both how the data that I'm querying is being stored, and of assumptions that the Query class seems to be making about the data.
The layers that I am querying regularly hold date-time information. All of the date-time fields associated with these layers are stored in a DBMS with the data type timestamp without timezone. Because geometric information is included with each piece of data a timezone could be retroactively computed and applied, and I think that this would be a much better practice, but ultimately I'm not at liberty to make those kinds of changes at this time. My requirements specify that I should provide date-time information as a timestamp with no associated timezone.
When this date-time information is queried with the Query and QueryTask classes, however, it is returned with an incorrectly associated timezone, and as a result, an improper localization. Somewhere during the process of executing the query and returning the result set, an assumption seems to be made that a timestamp without a timezone should be associated with the timezone UTC±00:00. The result set is also localized, and as such the timestamp returned is temporally relative to the timezone UTC±00:00, which results in an incorrectly localized timestamp.
What I'd really like is a way to use the Query object to specify that I'd like date-time information to be returned as the raw data stored in the database without any formatting, appended timezones, or localization.
My actual solution has been to revert the localization by converting the timezone back from a localized zone to UTC±00:00, and then to just manually drop the timezone from the timestamp. This accomplishes the same thing, albeit with an additional date formatting function that wouldn't be necessary if the result set could just return the information exactly as it exists in the database.
Modifying the query such that it returns an accurate result set is preferred to using a function to process incorrectly returned dates. The first reason is performance. For larger queries, the need to spend time processing dates can be significant, and could be avoided entirely. The second reason is maintenance. It would be significantly easier to maintain a few configuration settings related to the API than to maintain a function that could need modifications if the API version is advanced and my project upgrades.

Angular app and internationalization and localization

we have an existing silverlight app which runs in browser + on hardware.
we want to rewrite this app using angular js and html5.
one of the key requirements with new system is support of internationalization and localization. and target countries are usa, brazil, italy for now.
Am new to this area and have lot of basic questions.
does existing database needs to be redesigned to support same ? i mean to identify columns (product_name/customer_name etc) that needs to have locale specific data and then store data for each locale and modify sprocs and webapi to accept language parameter and then get content based on that. ?
I believe we need to user nvarchar for such columns.
what will happen to currency and date time columns in db ? say there is quantity column then what should be data type of this column in db ? if current locale is Portuguese then will qty stored in Portuguese number.
what is the best practices for storing and retrieving currency column
based on locale.
what is the best practices for storing and retrieving date column
based on locale.
how to handle string checks, numeric checks in webapi methods ?
how to do comparison and checks in javascript for string,number,datetime
please share link to some good pointers which could help.
so in short right from javascript to .net webapi to database (sql) how should we take care of locale dependent logic and fields
thanks.
A lot of questions, let's see if I can answer those.
If your existing application is properly internationalized, I don't think there is any need to modify the database. Just make sure it is able to handle international characters (NCHAR, NVARCHAR, NTEXT in MS SQL, valid character encodings in others).
As for DB design, it is good to keep things locale-independent as long as you can. For instance it is better to store keys in the database and resolve them at runtime. However, if your data is dynamic (i.e. you have product names and their descriptions that changes often), the only way to go is to have translation table and look the data up using valid locale. It's quite complex in relational world (i.e. joins), but it could be done.
2,3. All the numeric columns should be kept locale-independent and formatted on the UI side. The more problematic would be prices and sales orders - you would need an additional column to store the currency code (i.e. 12.34 | USD). On the UI side you would need to pass the code to the Angular currency filter. The only gotcha here is, Angular does not support easy locale context switching, so you would need to use a hacky library like Angular Dynamic Locale to load the formats for you.
Similar. Keep it locale-independent. DB built-in types should automatically handle that for you and give you nice DateTime/DateTimeOffset (in a .Net world) back. The only gotcha would be the time zone - it may make sense to use DATETIMEOFFSET MS SQL type, as others does not store time zone.
There is an alternative way to store date and times in the database - you may decide to store it as a number of milliseconds since January 1, 1970 UTC - as BIGINT type. Especially if you are going to read this directly to JS, you will be able to easily re-create JS Date object (should you need this for calculations or something) in a valid time zone (it works the other way round as well). All you have to do to format date is to use this number (not date, that is AFAIR) and Angular's date filter with UTC as a parameter.
I don't think I understand what you're asking exactly. I guess the question is about validation of user input, rather than API. Well, beware of using Regular Expressions, because JavaScript doesn't handle Unicode well (at least in this area). You'd need to ask more precise question.
Assuming that you have Number and Date objects (i.e. typeof o == 'number') it is straightforward (as in obj1 === obj2).
As far as strings are concerned... Well, str1 === str2 will give you valid answer if you want to be exact. If you want to sort them, modern web browsers (Chrome 14+, Firefox 29+, IE11+) implement EcmaScript 402 Internationalization API so you can do something like str1.localeCompare(str2, locale), see this article.
The real problem occurs when you want to compare two strings case insensitive and accent insensitive for equality (as oppose for ordering like in case of sorting). Basically, there is no way (and this is true even in "big" programming languages like Java or C#).

Asp-net web api output datetime with the letter T

the data in the DB look like this
2011-09-07 14:43:22.520
But my Web API outputs the data and replace the space with the letter T
2011-09-07T14:43:22.520
I can replace the letter T with a space again in jquery, but can I fix this problem from the Web API (make the web api output the original data?)
I also do not want the miliseconds at the end. How can I get rid of them?
The format of how you see the date in the database is usually irrelevant, because it should be passed into .Net as a DateTime - not as a string. (If you are storing it as a varchar in the database, you have a bigger problem.)
ASP.Net WebAPI is returning the value in format defined by ISO8601 and RFC3339. This is a good thing, as it is a recognized machine-readable format. You probably don't want to change it.
If you really want to change it, you would need to implement a custom JSON.Net JsonConverter, deriving from DateTimeConverterBase. This is discussed here and here.
But instead, you should consider how you are using the actual result in your client application. You mentioned jQuery, so I will assume your consumer is JavaScript. In many browsers, the ISO8601 value that you have is already recognized by the JavaScript Date constructor, so you might be able to just do this:
var dt = new Date("2011-09-07T14:43:22.520");
But this won't work in all browsers. And Date doesn't have a whole lot of flexibility when it comes to formatting. So instead, you might want to consider a library such as moment.js. With that in place, you can do this:
var m = moment("2011-09-07T14:43:22.520");
var s = m.format("YYYY-MM-DD HH:mm:ss"); // output: "2011-09-07 14:43:22"
Please note that the format string here conforms to moment.js, not to .NET. There are differences in case sensitivity. Please refer to the moment.js documentation for details.
One other thing - since the value you provided doesn't have either a Z at the end, nor does it have an offset such as -07:00, then I assume it came from a DateTime whos .Kind value is DateTimeKind.Unspecified. You should be aware that when this gets sent into JavaScript (or anywhere else for that matter), there is no information about what time zone is represented. JavaScript will assume the local time zone of the browser.
If that's not what you had intended, then you need to store UTC values in your database, and make sure they have DateTimeKind.Utc so they get serialized with a Z at the end. JavaScript will normalize this to the browser's time zone, but you will still be talking about the same moment in time.
Alternatively, you could use a DateTimeOffset type - which would serialize with the specific offset. JavaScript will still normalize this to the user's time zone.

Saving and updating the state of an AJAX based graph in Rails

I have a Google Chart's ColumnChart in a Rails project. This is generated and populated in JavaScript, by calling a Rails controller action which renders JSON.
The chart displays a month's worth of information for a customer.
Above the chart I have next and previous arrows which allow a customer to change the month displayed on the chart. These don't have any functionality as it stands.
My question is, what is the best way to save the state of the chart, in terms of it's current month for a customer viewing the chart.
Here is how the I was thinking of doing the workflow:
One of the arrows is selected.
This event is captured in JavaScript.
Another request to the Rails action rendering JSON is performed with an additional GET parameter
passed, based on an data attribute of the arrow button (Either + or - ).
The chart is re-rendered using the new JSON response.
Would the logic around incrementing or decrementing the graphs current date be performed on the server side? With the chart's date being stored in a session array defaulting to the current date on first load?
On the other hand would it make sense to save the chart state on the client side within the JavaScript code or in cookie, then manipulate the date before it's sent to the Rails controller?
I've been developing with Rails for about 6 months and feel comfortable with it, but have only just recently started developing with JavaScript, using AJAX. My experience tying JS code together with Rails is some what limited at this point, so looking for some advice/best practices about how to approach this.
Any advice is much appreciated.
I'm going to go through a couple of options, some good, some bad.
First, what you definitely don't want to do is maintain any notion of what month you are in in cookies or any other form of persistent server-side storage. Certainly sometimes server state is necessary, but it shouldn't be used when their are easy alternatives. Part of REST (which Rails is largely built around) is trying to represent data in pure attributes rather than letting it's state be spread around like that.
From here, most solutions are probably acceptable, and opinion plays a greater role. One thing you could do is calculate a month from the +/- sign using the current month and send that to the server, which will return the information for the month requested.
I'm not a huge fan of this though, as you have to write javascript that's capable of creating valid date ranges, and most of this functionality will probably be on the server already. Just passing a +/- and the current month to the server will work as well, you'll just have to do a bit of additional routing and logic to resolve the sign on the server to a different month.
While either of these would work, my preferred solution would instead have the initial request for the month generate valid representations of the neighbouring months, and returning this to the client. Then, when you update the graph with the requested data, you also replace the forward/backward links on the graph with the ones provided by the server. This provides a nice fusion of the benefits of the prior two solutions - no additional routing on the server, and no substantive addition to the client-side code. Also, you have the added benefit of being able to grey out transitions to months where no data was collected from the client (i.e. before they were a customer and the future). Without this, you'd have to create separate logic to handle client requests for information that doesn't exist, which is extra work for you and more confusion for the customer.

Localize dates on a browser?

Let's say I have a date that I can represent in a culture-invariant format (ISO 8601).
I'll pick July 6, 2009, 3:54 pm UTC time in Paris, a.k.a. 5:54 pm local time in Paris observing daylight savings.
2009-07-06T15:54:12.000+02:00
OK... is there any hidden gem of markup that will tell the browser to convert that string into a localized version of it?
The closest solution is using Javascript's Date.prototype.toLocaleString(). It certainly does a good job, but it can be slow to iterate over a lot of dates, and it relies on Javascript.
Is there any HTML, CSS, XSLT, or otherwise semantic markup that a browser will recognize and automatically render the correct localized string?
Edit:
The method I am currently using is replacing the text of an HTML element with a localized string:
Starting with:
<span class="date">2009/07/06 15:54:12 GMT</span>
Using Javascript (with jQuery):
var dates = $("span.date", context);
// use for loop instead of .each() for speed
for(var i=0,len=dates.length; i < len; i++) {
// parse the date
var d = new Date(dates.eq(i).text());
// set the text to the localized string
dates.eq(i).text(d.toLocaleString());
}
From a practical point of view, it makes the text "flash" to the new value when the Javascript runs, and I don't like it.
From a principles point of view, I don't get why we need to do this - the browser should be able to localize standard things like currency, dates, numbers, as long as we mark it up as such.
A follow up question: Why do browsers/the Web not have such a simple feature - take a standard data item, and format it according to the client's settings?
I use toLocaleString() on my site, and I've never had a problem with the speed of it. How are you getting the server date into the Date object? Parsing?
I add a comment node right before I display the date as the server sees it. Inside the comment node is the date/time of that post as the number of milliseconds since epoch. In Rails, for example:
<!--<%= post.created_at.to_i * 1000 %>-->
If they have JS enabled, I use jQuery to grab those nodes, get the value of the comment, then:
var date = new Date();
date.setTime(msFromEpoch);
// output date.toLocaleString()
If they don't have JS enabled, they can feel free to do the conversion in their head.
If you're trying to parse the ISO time, that may be the cause of your slowness. Also, how many dates are we talking?
Unfortunately, there is not.
HTML & CSS are strictly used for presentation, as such, there is no "smarts" built in to change the way things are displayed.
Your best bet would be to use a server side language (like .NET, Python, etc.) to emit the dates into the HTML in the format you want them shown to your user.
It is not possible to do this with HTML, it has no smart tags that can make any kind of decisions like this. It is strictly presentational. I do wonder, though, if HTML5 perhaps has a tag for something like this...
Anyways, the way I see it, you have 3 options:
Stick to the Javascript way. There's questions with more details on it on this website, such as How do I display a date/time in the user’s locale format and time offset? and How can I determine a web user’s time zone?
Try to use geolocation. That is, your server side script fires off a request to one of the many geolocator services out there on the user's first page visit to try and guess where the user is. The downside of this is that it will be wrong about 10% of the time, so it's not that much better than the market share Javascript is going to get you.... (all in all, then, not a very good method...)
Ask the user! You will see that most websites that want to display a tailored experience for you will ask you this sort of thing because it's just not possible to know. As a neat fallback, you could wrap the question around <noscript> tags so you only ask those with Javascript disabled while offering the Javascript experience to those that have it.
Dojo has some pretty good localizations for dates and currencies. Using this method also allows you to pick different formats (e.g.: short date vs long date) and force locales.
The language and the user's locale should be sent on the HTTP header. You can use those to create the correct date format server-side to be displayed to the user. However, this is often undesirable because many users completely ignore their locale settings in their OS and/or browser. So, you may be feeding USA style timestamps to New Zealanders.
I liked the trick posted in the comment above, but it sounds like a QA headache, since you could be dealing with a large number of clients that implement timestamps in very different ways.
The most effective solution I have seen, is to simple provide a panel to allow your users to choose what time format they like. Some users even ****gasp**** like ISO formats. Then you do the time format conversion server side. If your application language does not have good locale to timezone formatting mapping, check your database. Many databases provide locale-based customized timezone formatting as well.
Because this anwser still popups in google I share that this is now possible to do by using a readonly datetime-local input (see below) and you can then style the input the way you want:
<input type="datetime-local" value="2018-06-12T19:30" readonly />
For more information see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/datetime-local

Categories

Resources