Kevon
Kevon

Reputation: 137

Timezone Offset in Angular JS and Rails

Background: I'm building an app with Angular JS as web interface and Rails API. The problem I am having is passing a date from Angular to Rails.

Issue: I have a form with a Date of Birth date field, when a user inputs his DOB say March 1st, 1985, Angular interprets it as 1985-03-01 00:00 +0800 (if you're in Hong Kong or Singapore) and sends a request to Rails. The first thing Rails does with it is to convert it to UTC, which means the datetime is now 1985-02-28 16:00 UTC. Therefore, when the date is saved to the database date column, it becomes Feb 28, 1985.

Solution for now: What I'm doing now is on Angular side, I get the Timezone offset hours and add it to the date, so instead of 1985-03-01 00:00 +0800, it is now 1985-03-01 08:00 +0800. When Rails get it, it converts to 1985-03-01 00:00 UTC and so saves the correct date to db. However, I believe this is a better alternative to tackle this issue.

Thinking about parsing just the date in Rails, yet the params[:dob] I see is already UTC by the time I get it. Would love to know if there is a better practice than my current solution. Thank you for any comment and feedback.

Upvotes: 3

Views: 1199

Answers (1)

Matt Johnson-Pint
Matt Johnson-Pint

Reputation: 241603

This problem is actually quite common, and stems from two separate but related issues:

  • The JavaScript Date object is misnamed. It's really a date + time object.

  • The JavaScript Date object always takes on the characteristics of the time zone for the environment in which it is running in.

For a date-only value like date-of-birth, the best solution to this problem is to not send a full timestamp to your server. Send just the date portion instead.

  • First, add 12 hours to the time, to use noon instead of midnight. This is to avoid issues with daylight saving time in time zones like Brazil, where the transition occurs right at midnight. (Otherwise, you may run into edge cases where the DOB comes out a day early.)

  • Then output the date portion of the value, as a string in ISO format (YYYY-MM-DD).

Example:

var dt = //  whatever Date object you get from the control
dt.setHours(dt.getHours() + 12); // adjust to noon
var pad = function(n) { return (n < 10 ? '0' : '') + n; }
var dob = dt.getFullYear() + '-' + pad(dt.getMonth()+1) + '-' + pad(dt.getDate());

Another common way to do this is:

var dt = //  whatever Date object you get from the control
dt.setHours(dt.getHours() + 12); // adjust to noon
dt.setMinutes(dt.getMinutes() - dt.getTimezoneOffset()); // adjust for the time zone
var dob = dt.toISOString().substring(0,10); // just get the date portion

On the Rails side of things, use a Date object instead of a DateTime. Unlike JavaScript, the Rails Date object is a date-only object - which is perfect for a date-of-birth.

Upvotes: 1

Related Questions