Giter Club home page Giter Club logo

timezone-js's Introduction

TimezoneJS.Date

Build Status

A timezone-enabled, drop-in replacement for the stock JavaScript Date. The timezoneJS.Date object is API-compatible with JS Date, with the same getter and setter methods -- it should work fine in any code that works with normal JavaScript Dates.

Mailing list

Overview

The timezoneJS.Date object gives you full-blown timezone support, independent from the timezone set on the end-user's machine running the browser. It uses the Olson zoneinfo files for its timezone data.

The constructor function and setter methods use proxy JavaScript Date objects behind the scenes, so you can use strings like '10/22/2006' with the constructor. You also get the same sensible wraparound behavior with numeric parameters (like setting a value of 14 for the month wraps around to the next March).

The other significant difference from the built-in JavaScript Date is that timezoneJS.Date also has named properties that store the values of year, month, date, etc., so it can be directly serialized to JSON and used for data transfer.

Setup

This section shows the most common way of setting up timezone-js. In the 'Customizing' section below you can find alternative approaches.

First you'll need to include the code on your page. Both timezoneJS.Date, and the supporting code it needs in timezoneJS.timezone are bundled in the date.js file in src directory. Include the code on your page with a normal JavaScript script include, like so:

<script type="text/javascript" src="/js/timezone-js/src/date.js">

Next you'll need the Olson time zone files -- timezoneJS.Date uses the raw Olson data to calculate timezone offsets. The Olson region files are simple, structured text data, which download quickly and parse easily. (They also compress to a very small size.)

Here is an example of how to get the Olson time zone files:

##!/bin/bash

# NOTE: Run from your webroot

# Create the /tz directory
mkdir tz

# Download the latest Olson files
curl ftp://ftp.iana.org/tz/tzdata-latest.tar.gz -o tz/tzdata-latest.tar.gz

# Expand the files
tar -xvzf tz/tzdata-latest.tar.gz -C tz

# Optionally, you can remove the downloaded archives.
rm tz/tzdata-latest.tar.gz

Then you'll need to make the files available to the timezoneJS.timezone code, and initialize the code to parse your default region. (This will be North America if you don't change it). No sense in downloading and parsing timezone data for the entire world if you're not going to be using it.

Put your directory of Olson files somewhere under your Web server root, and point timezoneJS.timezone.zoneFileBasePath to it. Then call the init function. Your code will look something like this:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.init({ callback: cb });

If you use timezoneJS.Date with Fleegix.js, jQuery or jQuery-compatible libraries (like Zepto.js), there's nothing else you need to do -- timezones for North America will be loaded and parsed on initial page load, and others will be downloaded and parsed on-the-fly, as needed. If you want to use this code with some other JavaScript toolkit, you'll need to overwrite your own transport method by setting timezoneJS.timezone.transport = someFunction method. Take a look at test-utils.js in spec for an example.

NOTE: By default init() is async so you'll need to specify a callback function such as init({ callback: cb }). Otherwise set init({ async: false }) to turn off async.

Usage

The timezoneJS.Date constructor is compatible to the normal JavaScript Date constructor, but additional allows to pass an optional tz (timezone). In the following cases the passed date/time is unambiguous:

timezoneJS.Date(millis, [tz])
timezoneJS.Date(Date, [tz])
timezoneJS.Date(dt_str_tz, [tz])

dt_str_tz is a date string containing timezone information, i.e. containing Z, T or a timezone offset matching the regular expression /[+-][0-9]{4}/ (e.g. +0200). The one-stop shop for cross-browser JavaScript Date parsing behavior provides detailed information about JavaScript date formats.

In the following cases the date is assumed to be a date in timezone tz or a locale date if tz is not provided:

timezoneJS.Date(year, mon, day, [hour], [min], [second], [tz])
timezoneJS.Date(dt_str, [tz])

dt_str is a date string containing no timezone information.

Examples

Create a timezoneJS.Date the same way as a normal JavaScript Date, but append a timezone parameter on the end:

var dt = new timezoneJS.Date('10/31/2008', 'America/New_York');
var dt = new timezoneJS.Date(2008, 9, 31, 11, 45, 'America/Los_Angeles');

Naturally enough, the getTimezoneOffset method returns the timezone offset in minutes based on the timezone you set for the date.

// Pre-DST-leap
var dt = new timezoneJS.Date(2006, 9, 29, 1, 59, 'America/Los_Angeles');
dt.getTimezoneOffset(); => 420
// Post-DST-leap
var dt = new timezoneJS.Date(2006, 9, 29, 2, 0, 'America/Los_Angeles');
dt.getTimezoneOffset(); => 480

Just as you'd expect, the getTime method gives you the UTC timestamp for the given date:

var dtA = new timezoneJS.Date(2007, 9, 31, 10, 30, 'America/Los_Angeles');
var dtB = new timezoneJS.Date(2007, 9, 31, 12, 30, 'America/Chicago');
// Same timestamp
dtA.getTime(); => 1193855400000
dtB.getTime(); => 1193855400000

You can set (or reset) the timezone using the setTimezone method:

var dt = new timezoneJS.Date('10/31/2006', 'America/Juneau');
dt.getTimezoneOffset(); => 540
dt.setTimezone('America/Chicago');
dt.getTimezoneOffset(); => 300
dt.setTimezone('Pacific/Honolulu');
dt.getTimezoneOffset(); => 600

The getTimezone method tells you what timezone a timezoneJS.Date is set to:

var dt = new timezoneJS.Date('12/27/2010', 'Asia/Tokyo');
dt.getTimezone(); => 'Asia/Tokyo'

You can use getTimezoneAbbreviation method to get timezone abbreviation:

var dt = new timezoneJS.Date('10/31/2008', 'America/New_York');
dt.getTimezoneAbbreviation(); => 'EDT'

Customizing

If you don't change it, the timezone region that loads on initialization is North America (the Olson 'northamerica' file). To change that to another reqion, set timezoneJS.timezone.defaultZoneFile to your desired region, like so:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.defaultZoneFile = 'asia';
timezoneJS.timezone.init();

If you want to preload multiple regions, set it to an array, like this:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.defaultZoneFile = ['asia', 'backward', 'northamerica', 'southamerica'];
timezoneJS.timezone.init();

By default the timezoneJS.Date timezone code lazy-loads the timezone data files, pulling them down and parsing them only as needed.

For example, if you go with the out-of-the-box setup, you'll have all the North American timezones pre-loaded -- but if you were to add a date with a timezone of 'Asia/Seoul,' it would grab the 'asia' Olson file and parse it before calculating the timezone offset for that date.

You can change this behavior by changing the value of timezoneJS.timezone.loadingScheme. The three possible values are:

  1. timezoneJS.timezone.loadingSchemes.PRELOAD_ALL -- this will preload all the timezone data files for all reqions up front. This setting would only make sense if you know your users will be using timezones from all around the world, and you prefer taking the up-front load time to the small on-the-fly lag from lazy loading.
  2. timezoneJS.timezone.loadingSchemes.LAZY_LOAD -- the default. Loads some amount of data up front, then lazy-loads any other needed timezone data as needed.
  3. timezoneJS.timezone.loadingSchemes.MANUAL_LOAD -- Preloads no data, and does no lazy loading. Use this setting if you're loading pre-parsed JSON timezone data.

Ready-made tzdata NPM modules

If you use NPM, and you want to load the time zone data synchronously, you can use one or more of the tzdata* NPM modules. That way, you do not have to download the IANA zone files manually, you can just run npm update to get the latest data.

The tzdata module contains all time zones. There are other modules, e.g. tzdata-northamerica that contain subsets of the zones.

First, install timezone-js and one or more of the tzdata modules.

npm install timezone-js tzdata

Then, initialize timezone-js with the data:

var timezoneJS = require("timezone-js");
var tzdata = require("tzdata");

var _tz = timezoneJS.timezone;
_tz.loadingScheme = _tz.loadingSchemes.MANUAL_LOAD;
_tz.loadZoneDataFromObject(tzdata);

var dt = new timezoneJS.Date(2006, 9, 29, 1, 59, 'America/Los_Angeles');

Pre-Parsed JSON Data

If you know beforehand what specific cities your users are going to be using, you can reduce load times specifically by creating a pre-parsed JSON data file containing only the timezone info for those specific cities.

The src directory contains 2 command-line JavaScript scripts that can generate this kind of JSON data:

  • node-preparse.js: Uses Node to preparse and populate data.
  • preparse.js: This script requires the Rhino (Java) JavaScript engine to run, since the stock SpiderMonkey (C) engine doesn't come with file I/O capabilities.

Use the script like this:

rhino preparse.js zoneFileDirectory [exemplarCities] > outputfile.json

Or:

node node-preparse.js zoneFileDirectory [exemplarCities] > outputfile.json

The first parameter is the directory where the script can find the Olson zoneinfo files. The second (optional) param should be a comma-delimited list of timzeone cities to create the JSON data for. If that parameter isn't passed, the script will generate the JSON data for all the files.

rhino preparse.js olson_files \
"Asia/Tokyo, America/New_York, Europe/London" \
> major_cities.json

rhino preparse.js olson_files > all_cities.json

Or:

node node-preparse.js olson_files \
"Asia/Tokyo, America/New_York, Europe/London" \
> major_cities.json

node node-preparse.js olson_files > all_cities.json

Once you have your file of JSON data, set your loading scheme to timezoneJS.timezone.loadingSchemes.MANUAL_LOAD, and load the JSON data with loadZoneJSONData, like this:

var _tz = timezoneJS.timezone;
_tz.loadingScheme = _tz.loadingSchemes.MANUAL_LOAD;
_tz.loadZoneJSONData('/major_cities.json', true);

Since the limited set of data will be much smaller than any of the zoneinfo files, and the JSON data is deserialized with eval or JSON.parse, this method is significantly faster than the default setup. However, it only works if you know beforehand exactly what timezones you want to use.

Compressing

The Olson timezone data files are simple, space- and linefeed-delimited data. The abundance of whitespace means they compress very, very well.

If you plan to use timezoneJS.Date in a production Web app, it's highly recommended that you first strip the copious comments found in every Olson file, and serve compressed versions of the files to all browsers that can handle it. (Note that IE6 reports itself as able to work with gzipped data, but has numerous problems with it.)

Just to give you an idea of the difference -- merely stripping out the comments from the 'northamerica' file reduces its size by two-thirds -- from 103K to 32K. Gzipping the stripped file reduces it down to 6.5K -- probably smaller than most of the graphics in your app.

The src directory has a sample Ruby script that you can use to strip comments from Olson data files.

Development

This project use Jake to build. In order to see available tasks, do jake -T. The build sequence is:

  • jake test:init: Download and extract tz files to lib/tz.
  • jake test: Run jasmine-node.

Feel free to fork and modify at your own will. The source code is annotated and doc can be generated with jake doc.

License

Copyright 2010 Matthew Eernisse ([email protected]) and Open Source Applications Foundation.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Credits: Ideas included from incomplete JS implementation of Olson parser, "XMLDAte" by Philippe Goetz ([email protected])

Contributions:

timezone-js's People

Contributors

ajnasz avatar beeftornado avatar berzniz avatar chotiwat avatar divide0 avatar ecanner avatar eugeneloy avatar houqp avatar itsuryev avatar jamieruderman avatar jannic avatar jgable avatar korun avatar longlho avatar lumbric avatar mde avatar mnpenner avatar oradwell avatar prozacgod avatar punkchameleon avatar reavis avatar scarlson-synegen avatar schickling avatar sdemjanenko avatar shosokawa avatar slexaxton avatar trosenblatt-zz avatar vasvitaly avatar vogievetsky avatar wrodenbusch avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

timezone-js's Issues

timezone-js doesn't work with flot.time

I want to use the new timezone-support in flot master branch (which uses timezone-js as backend). Unfortunately this doesn't work out of the box for me. I need to apply the following patch to timezone-js and then (with another patch to flot, see http://code.google.com/p/flot/issues/detail?id=713) everything works fine.

The patch seems wrong to me in the sense that I'm trampling the semantics, but it Works For Me(tm).

Here comes the patch (why dosn't github allow attachments?):

From 8d12c8bd72d91214ef595f72aeb7891dcd750749 Mon Sep 17 00:00:00 2001
From: Markus Oehme 
Date: Thu, 5 Jul 2012 15:44:12 +0200
Subject: [PATCH] Magic fix.

I don't know why it works, but it does. The handling of UTC or local ._dateProxy objects seems bogus. It should be always UTC to cause less trouble.

---
 src/date.js |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/src/date.js b/src/date.js
index a4db1af..721852d 100644
--- a/src/date.js
+++ b/src/date.js
@@ -349,7 +349,7 @@
       var dt = this._dateProxy;
       var meth = unit === 'year' ? 'FullYear' : unit.substr(0, 1).toUpperCase() + unit.substr(1);
       dt['set' + meth](n);
-      this.setFromDateObjProxy(dt);
+   this.setFromDateObjProxy(dt, true);
     },
     setUTCAttribute: function (unit, n) {
       if (isNaN(n)) { throw new Error('Units must be a number.'); }
-- 
1.7.5.4

Needs transport capability using ExtJS

I am planning to implement this, and to submit a pull request when it's ready. I don't see specific test cases for the different javascript libraries as transport, nor do I see where any particular library is included into the test suite. Can someone explain please? Thanks.

timezone-js doesn't handle static dst offset rules

Example is Pacific/Apia, in the australasia file

Zone Pacific/Apia    12:33:04 - LMT 1879 Jul  5
            -11:26:56 - LMT 1911
            -11:30  -   SAMT    1950        # Samoa Time
            -11:00  -   WST 2010 Sep 26
            -11:00  1:00    WSDT    2011 Apr 2 4:00
            -11:00  -   WST 2011 Sep 24 3:00
            -11:00  1:00    WSDT    2011 Dec 30
             13:00  1:00    WSDT    2012 Apr 1 4:00
             13:00  -   WST

Notice that instead of referencing DST rules, they just put the DST offset.

Instantiating now or passing another date

Is there a way to instantiate a timezone-js date of now? (ie: like new Date())

Also, is there a way to convert an existing date object into a timezone-js date?

Thanks!

Using built-in Date in local time zone as a backend of timezone-js is a fundamental mistake

Suppose my system timezone is Pacific Time. See this example:

> new Date(2012,2,11,1,59,0);
Sun Mar 11 2012 01:59:00 GMT-0800 (PST)
> new Date(2012,2,11,2,0,0);
Sun Mar 11 2012 01:00:00 GMT-0800 (PST)
> new Date(2012,2,11,3,0,0);
Sun Mar 11 2012 03:00:00 GMT-0700 (PDT)

When using the local timezone, there exists date that simply doesn't exist. Therefore, you shouldn't use the built-in Date in the local timezone as the internal representation of the timezoneJS.Date. However, you are doing this all over your code.

A solution to this issue is to use the UTC time of the built-in Date to represent the timezoneJS.Date, which is guaranteed to work, as long as we don't take Gregorian cut-off time into consideration.

I appreciate your work. This indeed is something useful if correct. And it's great that you're willing to help the community and make it available to everyone. However, This issue and issue #36, are both critical enough that warrants immediate fix. Given issue #36 has been outstanding for quite some time, you probably won't have time to fix both bugs any time soon. Currently, when searching for time zone conversion in js on Google, several top results are directing users to try your code here. Therefore, I believe you should put a noticeable warning on this project's main readme to advise any serious user that wants accurate time conversion to avoid using this code and find alternatives.

TimeZone def without time is assumed to be 23:59:59 of same date. Wrong assumption

Example is Pacific/Apia, in the australasia file.

They switched from GMT-11 to GMT+13 on Dec 30 at midnight

# Dateline Change skip Friday 30th Dec 2011
# Thursday 29th December 2011   23:59:59 Hours
# Saturday 31st December 2011   00:00:00 Hours

[snip]

Zone Pacific/Apia    12:33:04 - LMT 1879 Jul  5
            -11:26:56 - LMT 1911
            -11:30  -   SAMT    1950        # Samoa Time
            -11:00  -   WST 2010 Sep 26
            -11:00  1:00    WSDT    2011 Apr 2 4:00
            -11:00  -   WST 2011 Sep 24 3:00
            -11:00  1:00    WSDT    2011 Dec 30
             13:00  1:00    WSDT    2012 Apr 1 4:00
             13:00  -   WST

Timezone-js just appends 23:59:59 if there is no time. This puts the transition at the wrong time.

error on Indian timezones

    var findApplicableRules = function( year, ruleset )
    {
      var applicableRules = [];

      for (var i = 0; i < ruleset.length; i++)
      {

should be

    var findApplicableRules = function( year, ruleset )
    {
      var applicableRules = [];

      for (var i = 0; ruleset && i < ruleset.length; i++)
      {

because otherwise I get an an error on Indian timezones.

toISOString() needs to convert to UTC or include tz offset

toISOString outputs times in the timezoneJS.Date's set timezone, but outputs with a "Z" appended which means UTC time.

Correct behavior is to either convert to UTC before outputting ISO8601 strings with "Z" appended, or include the offset (-10:00, +05:00, etc). Most implementations do the former.

Broken in Firefox 3.6

Minimal test-case:

var dt = new timezoneJS.Date(2012, 9, 8, 0, 0, 0, "Pacific/Honolulu");
dt.toJSON();

>>> Error: Units must be a number.

Not sure what's causing this only in Firefox 3.6; it looks like timezone.getTzInfo isn't set at the time toString() is called. IE, newer Firefoxes, and Chrome works fine.

toGMTString() error

When calling toGMTString(), I get this error:

Error: Timezone "GMT" is either incorrect, or not loaded in the timezone registry.

I do have the backwards timezone loaded which has the GMT timezone and still get this error. It seems like the logic to find the timezone is not working properly.

12/24 hour formating in toString()

In date.js:236, you compute the hours for the toString format like:

var hou = this.getHours() || 12;

This means hour 0 and hour 12 are displayed the same way, which doesn't seem like what you want given that toString otherwise shows the time in 24-hour time. It causes confusing results like those below. I just removed the || 12; that seems like what is expected.

> point.setTime(1326846063000); point.toString()
"2012-1-18 12:21:03"

> point.setTime(1326846063000 + (3600 * 1000*12)); point.toString()
"2012-1-18 12:21:03"

Creating Date objects with abbreviated timezone names not working

The tests make it look like I should be able to create the date object in either of the following ways:

--(stuart@battra:pts/4)------------------(/home/stuart/src/hilary)(win-compat)--
--(1132:Wed,07 Nov 12:$)-- node
> var tz = require('timezone-js');
undefined
> var fs = require('fs');
undefined
> tz.timezone.zoneFileBasePath = '/home/stuart/src/hilary/node_modules/oae-util/tz';
'/home/stuart/src/hilary/node_modules/oae-util/tz'
> tz.timezone.transport = function(opts) {
...     if (opts.async) {
.....         if (typeof opts.success !== 'function') return;
.....         opts.error = opts.error || console.error;
.....         return fs.readFile(opts.url, 'utf8', function (err, data) {
.......             return err ? opts.error(err) : opts.success(data);
.......         });
.....     }
...     return fs.readFileSync(opts.url, 'utf8');
... };
[Function]
> tz.timezone.init();
undefined
> var date = new tz.Date(null, 'UTC');
undefined
> date
{ _useCache: false,
  _tzInfo: {},
  _day: NaN,
  year: NaN,
  month: NaN,
  date: NaN,
  hours: NaN,
  minutes: NaN,
  seconds: NaN,
  milliseconds: NaN,
  timezone: null,
  _dateProxy: Invalid Date,
  _timeProxy: NaN }
> var date = new tz.Date(null, 'Etc/UTC');
undefined
> date
{ _useCache: false,
  _tzInfo: {},
  _day: 4,
  year: 1970,
  month: 0,
  date: 1,
  hours: 0,
  minutes: 0,
  seconds: 0,
  milliseconds: 0,
  timezone: 'Etc/UTC',
  _dateProxy: Thu Jan 01 1970 00:00:00 GMT-0500 (EST),
  _timeProxy: 0 }
> 

But as you can see, the one using 'UTC' as the timezone isn't properly created. I tried running the test suite, but it looks like jasmine-node is buggy:

--(stuart@battra:pts/3)---(...src/hilary/node_modules/timezone-js)(win-compat)--
--(1141:Wed,07 Nov 12:$)-- jake test


Finished in 0 seconds
0 tests, 0 assertions, 0 failures

preparse.js doesn't work

I followed the instructions to preparse the tzdb data using preparse.js. The script didn't run at all. It got caught on this:

load('../../src/json.js');
var _tz = fleegix.date.timezone;

I pulled in fleegix and changed the path to point at json.js properly, then update the name of the library. (I'm guessing this is an old script that is out of sync with current changes)

load('src/json.js');  // where I have fleegix source dir
var _tz = timezoneJS.timezone;

Then the script ran, and built the json file. However, it wouldn't work in the current code. I dug in further and found that the json has a lot of arrays ending with undefined data:

["2:00",2,0,0,"undefined"]

I manually (search/replace) took out all of those so those data elements, making it look like

["2:00",2,0,0]

Then it worked. I dug through the script, but I can't seem to find how these extra fields are getting created.

Altering date doesn't work -- example code

I'm guessing setAttribute and/or timezoneJS.Date constructor needs some work. The following merely adds 1 day to a timezone-aware date, but the hours get messed up in the process.

var dt = new timezoneJS.Date();
dt.setTimezone('America/New_York');
x = dt.hours;
dt.setDate(dt.getDate() + 1);
y = dt.hours;
alert(x===y);

Is this related to the other issue I added regarding tzInfo not being copied to cloned dates?

Globally extending Array with indexOf method in old MSIE breaks other code

timezone-js extends the Array prototype with a missing indexOf method in MSIE:

//Handle array indexOf in IE   
if (!Array.prototype.indexOf) {
    Array.prototype.indexOf = function (el) {

Unfortunately that breaks other code - indexOf becomes a key in all Arrays:

    for (var idx in array_of_stuff)
            dostuff(idx);

That code will now call dostuff() with 'indexOf' with IE8 at least. For IE support the indexOf should be avoided, or it somehow needs to be added locally. I'll look into this myself and try to get a patch submitted soon.

Creating new timezoneJS.Date object using timestamp or existing Date object

In the README it states:

Create a timezoneJS.Date the same way as a normal JavaScript Date, but append a timezone parameter on the end

In JavaScript we can do following:

var date1 = new Date();
var date2 = new Date(date1.getTime());
var date3 = new Date(date2);

This will create new Date objects.
Both cases doesn't seem to work with timezoneJS.Date object. We have to do

var date = new Date();
var dt = new timezoneJS.Date(date.getFullYear(), date.getMonth(), ..., 'Asia/Tokyo');

This may be not an actual issue if it was not planned to support such use case but please consider it as useful feature request then.

Sugestion for improvement: static load of JSON data

Hi,

I'm trying to use this library in my symfony2 project, where I have TWO virtual hosts, host (A) for the website and host (B) for the static contents like js, css, img.

Since I suppose the timezone json data (generated with node-parse.js) is relatively static, I'd like to put it under host (B). However, since the website is on host (A), I found that either in sync/async mode, it failed to load the json data file. After several struggling, I realized that it is a cross-origin request which is by-default not allowed, unless I set some Apache directive to allow the cross-domain visit.

Also, I found that "processData()" is a private function in the library which is the core for assign the JSON data into your timezone object. If this function can be reached by the user, I can include the json content, and then pass the json structure into this function. This saves me a request.

Maybe only I have such a requirement as I'd like to load timezones for all countries beforehand. Pls consider this. Thanks.

Simon

Create shorter alias names for timezoneJS and timezone

Perhaps:

tzjs = timezoneJS;
tzjs.tz = tzjs.timezone;

or anything, as long it uses less characters. Of course, any developer can make these aliases in their application, but perhaps it would be useful to make it official.

Lazy load happens async by default, should be sync

There are a couple errors here. Per the readme, I used the following code on page load:

timezoneJS.timezone.zoneFileBasePath = '/tz';
timezoneJS.timezone.init();

// Then I tried to create a date with a timezone
var dt = new timezoneJS.Date();
dt.setTimezone('America/Los_Angeles'); 

This results in an error. Internally, date.js reports loadedZones['northamerica'] == true, because it sets it so before it actually loads the file in loadZoneFile:

this.loadedZones[fileName] = true;
return builtInLoadZoneFile(fileName, opts);

That's the first error. This shouldn't be set until some kind of success from the loading occurs.

Also, in getTzInfo, even if this.loadedZones[fileName] returned false, you have this code:

if (!this.loadedZones[zoneFile]) {
      // Get the file and parse it -- use synchronous XHR
      this.loadZoneFile(zoneFile, true); // <-- Don't you mean {async: false} ?
}

The second parameter in the loadZoneFile call doesn't seem to be for anything -- loadZoneFile expects an object of options. More likely you mean {async: false} ?

For now, as a workaround, the above issues can be circumvented by just forcing async to false on init.

timezoneJS.timezone.init({async: false});

set* breaks the Date

Transcript from Chrome console:

> d = new timezoneJS.Date()
timezoneJS.Date
> d.toString()
"2012-06-08 08:29:19"
> d.setHours(6)
undefined
> d.toString()
"0NaN-NaN-NaN NaN:NaN:NaN"

Error when using .json file for timezone data

When using a .json file for timezone data instead of a folder generated through the

node node-preparse.js zoneFileDirectory > outputfile.json

command, I get the following error when setting a timezone

TypeError: Object 600 has no method 'match'
at parseTimeString (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:449:21)
    at getBasicOffset (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:494:17)
    at timezoneJS.timezone.getTzInfo (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:855:17)
    at Object.timezoneJS.Date.getTimezoneInfo (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:212:35)
    at Object.timezoneJS.Date.getTimezoneOffset (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:201:50)
    at Object.timezoneJS.Date.getUTCDateProxy (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:331:50)
    at Object.timezoneJS.Date.getUTCMinutes (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:227:46)
    at Object.timezoneJS.Date.setTimezone (/Users/mdedetrich/temp/node_modules/timezone-js/src/date.js:358:33)

600 happens to be the timezone for 'Pacific/Honolulu'. It appears that when the JSON file is parsed, timezone-js doesn't appear to convert the objects to a string, they instead remain as objects. Here is the tz.json I am using (that was generated through the above command) https://dl.dropbox.com/u/11630011/tz.json.

Also this is what my transport function looks like

timezoneJS.timezone.transport = function(opts) {
  return fs.readFileSync(opts.url, 'utf8');
};

This is being run on the latest version of node.js

Proposal: Make it easy to load zone file(s) based on zone area

I don't know why Olson did it this way, but the time zone area (e.g., America in America/New_York) does not map directly to the zone file (i.e., America could mean northamerica or southamerica).

It would be nice if timezoneJS had a way to specify zone areas to load, and it would automatically map to a zonefile for you. If there is ambiguity as to which zonefile it is (e.g., America could be either northamerica or southamerica), then load all possible zone files.

I'm probably going to implement this myself, but if someone wants to be beat me to the punch, be my guest.

setTimezone() should reset utc flag

When calling setTimezone, the utc flag is set but never reset. This means that if we are to go from UTC to another timezone, other parts of the code will still think we are in UTC.

Simple fix is just to change setTimezone, replace the if statement with:

this.utc = tz === 'Etc/UTC' || tz === 'Etc/GMT';

Fails to set timezone in IE8

When trying to set a timezone in IE8 it fails.

var d = new timezoneJS.Date();
d.setTimezone('Europe/Stockholm'); //  "Object doesn't support this property or method"

Only default timezones are preloaded even with PRELOAD_ALL enabled

Consider the following code:

timezoneJS.timezone.zoneFileBasePath = 'tz/';
timezoneJS.timezone.loadingScheme = timezoneJS.timezone.loadingSchemes.PRELOAD_ALL;
timezoneJS.timezone.init();

I would expect it to load all the timezones from the start but it loads only "northamerica". Am I missing something?
There is a workaround of course - simply include all the zones in the defaultZoneFile.

Setting UTC millis of DST transition then time zone results in wrong DST state

Code

            console.log("\n\nTesting timezone-js transition millis...\n");
            dt = new timezoneJS.Date(1162112399999);
            dt.setTimezone("America/Los_Angeles");
            console.log("1ms Before transition time: " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));
            dt = new timezoneJS.Date(1162112400000);
            dt.setTimezone("America/Los_Angeles");
            console.log("At transition time: " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));

Output

Testing timezone-js transition millis...
1ms Before transition time: Sun, 29 Oct 2006 01:59:59 PDT
At transition time: Sun, 29 Oct 2006 01:00:00 PDT

Result

Timezone-JS seems to have the right offset, but it still outputs PDT instead of PST

XDate like usage and formatting: TZDate

Over the weekend I hacked together a version of timezone-js with similar usage to XDate with the same formatting and locale support. To make it a bit easier to use and differentiate, I renamed it TZDate.

It's essentially a proof of concept and aims resolve the timezone problems I was having with XDate. It seems to be working well, timezoneJS's awesome timezone support with XDate's nice API and formatting makes things quite a bit easier.

I'm really not sure if this is a direction you would be interested in going in, it certainly isn't very compatible with current timezoneJS setups, but the source code is available here should you want to have a look: https://github.com/samlown/tzdate

Cheers, sam

Insert an inexistent time

For example in Madrid the DST change 3am to 2am at 10/27/2013 if you insert a hour between 1-3 the time result is a GMT 0:

var dt1 = new timezoneJS.Date(1382835540000, 'Europe/Madrid' ); ==> Sun Oct 27 2013 00:59:00 GMT+0
TimezoneJS.Date {_useCache: false, _tzInfo: Object, _day: 0, year: 2013, month: 9…}
_dateProxy: Sun Oct 27 2013 02:59:00 GMT+0200 (Hora de verano romance)

var dt2 = new timezoneJS.Date(1382835600000, 'Europe/Madrid' ); ==> Sun Oct 27 2013 01:00:00 GMT+0
TimezoneJS.Date {_useCache: false, _tzInfo: Object, _day: 0, year: 2013, month: 9…}
_dateProxy: Sun Oct 27 2013 03:00:00 GMT+0100 (Hora estándar romance)

var dt3 = new timezoneJS.Date(1382842740000, 'Europe/Madrid' ); ==> Sun Oct 27 2013 02:59:00 GMT+0
TimezoneJS.Date {_useCache: false, _tzInfo: Object, _day: 0, year: 2013, month: 9…}
_dateProxy: Sun Oct 27 2013 04:59:00 GMT+0100 (Hora estándar romance)

var dt3 = new timezoneJS.Date(1382842800000, 'Europe/Madrid' ); ==> Sun Oct 27 2013 03:00:00 GMT+0
TimezoneJS.Date {_useCache: false, _tzInfo: Object, _day: 0, year: 2013, month: 9…}
_dateProxy: Sun Oct 27 2013 04:00:00 GMT+0100 (Hora estándar romance)

Dates are off in timezones that use DST

Consider the following:

var ts1 = 1383451200000;
var dt = new timezoneJS.Date(ts1, 'America/New_York');
var ts2 = dt.getTime();

I would expect that ts2 would be equal to ts1 regardless of which timezone I provided, because they are supposed to be UTC. Instead, ts1 is 1383447600000

If I switch to a timezone that doesn't use DST, such as America/Phoenix or Asia/Kolkata then it works as expected.

Or am I wrong in thinking that the input or the output is supposed to be in UTC? The documentation isn't very clear about that. Thanks.

1/2 argument constructors with timezone do weird things

date.js lists this as a possible way to construct a date: timezoneJS.Date(utcMillis, [tz]): Return object with UTC time = utcMillis, in tz and states that getTime() returns UTC time.

However:

> a = new timezoneJS.Date(0, "Europe/London")
> a.getTime()
-3600000 // expect zero

I'm not sure if I've badly misinterpreted the documentation or this is broken. Indeed, this behaviour is even unit tested.

Some strange implications of this behaviour:

a = new timezoneJS.Date(2000, 6, 1, 0, 0, 0, "Europe/London")
a.toString() == "Fri, 30 Jun 2000 23:00:00 GMT"
for (i = 0; i < 1000; i++)
    a = new timezoneJS.Date(a, "Europe/London")
a.toString() == "Sat, 20 May 2000 07:00:00 GMT"

Finally, noting that my system/browser time is set to Europe/London;

(new timezoneJS.Date("Europe/London")).getTime()
1342523332306
(new timezoneJS.Date("Europe/Paris")).getTime()
1342519732306
(new timezoneJS.Date("Etc/UTC")).getTime()
1342526932306
(new Date()).getTime()
1342526932306
(a = (new timezoneJS.Date("Etc/UTC")), a.setTimezone("Europe/London"), a.getTime())
1342526932306

but I would expect all five of these numbers to be the same (the correct UNIX timestamp when I ran that was 1342526932)

loadZoneJSONData with sync=false, hms is null

I'm calling this:

timezoneJS.timezone.loadingScheme = timezoneJS.timezone.loadingSchemes.MANUAL_LOAD;
timezoneJS.timezone.loadZoneJSONData('/tz/all-tz.json', false);

My Firefox's Error Console shows me this error:

TypeError: hms is null

Which is this line:

    function parseTimeString(str) {
      var pat = /(\d+)(?::0*(\d*))?(?::0*(\d*))?([wsugz])?$/;
      var hms = str.match(pat);
      hms[1] = parseInt(hms[1], 10);             <-----------------This line
      hms[2] = hms[2] ? parseInt(hms[2], 10) : 0;
      hms[3] = hms[3] ? parseInt(hms[3], 10) : 0;

      return hms;
    }

But when I change it to sync=true:

timezoneJS.timezone.loadingScheme = timezoneJS.timezone.loadingSchemes.MANUAL_LOAD;
timezoneJS.timezone.loadZoneJSONData('/tz/all-tz.json', true);

It has no errors, and seems to work well. I've only tested Asia/Shanghai, America/Los_Angeles, America/New_York.

Any suggestions?

P.S.: all-tz.json was generated from:

node node-parse.js ./tz/ > ./tz/all-tz.json

and ./tz/ contains the files extracted from ftp://ftp.iana.org/tz/tzdata-latest.tar.gz, which I did it according to the README.md.

Simon

buggy loadingSchemes logic

Looks like the beginning of the init function should be:

def = this.loadingScheme === this.loadingSchemes.PRELOAD_ALL
          ? this.zoneFiles
          : this.loadingScheme === this.loadingSchemes.LAZY_LOAD
            ? (typeof this.defaultZoneFile === 'array'  || typeof this.defaultZoneFile === 'string' ? this.defaultZoneFile : 'northamerica')
            : def = [] // MANUAL_LOAD

instead of:

def = this.loadingScheme === this.loadingSchemes.PRELOAD_ALL
          ? this.zoneFiles
          : (this.defaultZoneFile ? this.defaultZoneFile : 'northamerica')

toJSON() missing

Ecmascript 5 adds a Date.toJSON() method that returns an ISO8601-formatted string, which we use liberally in our project (with appropriate shims for older browsers). Can we have an "official" implementation for timezoneJS.Date?

Can't load timezone with JQuery.

I am trying to get this to work with JQuery. I get the following error:

Uncaught Error: Timezone "America/Chicago" is either incorrect, or not loaded in the timezone registry.

The readme states I would need too create a custom transport method. Could anyone give an example on how I would do this or create a wiki for it. Sorry to create an issue, this has been driving me crazy!

how do i use this from within node.js?

there doesn't seem to be a proper node.js entry point. I'd really like to be able to

var timezones = require('timezone-js')
timezones.loadTimezonesSync()

str.split is not a function

I have just added the js. Then added these 2 lines of code

timezoneJS.timezone.zoneFileBasePath = "Timezone"; //Its in the same folder in a separate folder called timezone.
timezoneJS.timezone.init();

I get

str.split is not a function
var lines = str.split('\n')

line 811 date.js file...

I get that error on load itself.
Can you please help me on this..

Browser : Firefox

Is this something to do with the timezone path ??

Getting different results from the string constructor

My local time is "America/Chicago" (UTC-06:00).

new timezoneJS.Date(2013, 00, 01, "America/New_York").getTime() => 1357016400000 (correct)
but:
new timezoneJS.Date("01/01/2013", "America/New_York").getTime() => 1357020000000 (incorrect)

Also:
new timezoneJS.Date(2013, 00, 01, "America/Los_Angeles").getTime() => 1357027200000 (correct)
but:
new timezoneJS.Date("01/01/2013", "America/Los_Angeles").getTime() => 1357020000000 (incorrect)

Speed considerations in case of changing timezone in a tight loop

Let's say I have 500 appointments, each appointment have start and end dates (they are all timezoneJS.Date instances at this point).
Now I change timezone using select and want to iterate over each appointment and switch timezone both to start and end dates. Selected timezone is the same for all events.

Basically:

var timezone = "SomeTimezone";
var events = [];
for (var i=0; i<events.length; i++) {
    var ev = events[i];
    ev.start_date.setTimezone(timezone);
    ev.end_date.setTimezone(timezone);
}

That happens to be quite slow. Is that expected or are there ways to improve it from my side?

The most time consuming functions are:

       Name                       Calls     %        Own time
1. convertRuleToExactDateAndTime  44760   41.56%    1660.881ms
2. parseTimeString                92502   25.47%    1018.099ms
3. getZone                        3000    6.44%     257.474ms
4. compareDates                   31092   6.31%     252.205ms
5. getRule                        3000    4.32%     172.64ms
6. findApplicableRules            5778    4.08%     163.247ms

"null" in timezoneJS.timezone.getAllZones() results

This is how I initialize lib:

timezoneJS.timezone.zoneFileBasePath = "tzdata";
timezoneJS.timezone.defaultZoneFile = ["africa", "antarctica", "asia", "australasia", "europe", "northamerica", "southamerica"];

timezoneJS.timezone.init();

And now when I run:

timezoneJS.timezone.getAllZones() last position in the returned array is "null" string.

Specifying unaltered folder from olson downloads causes errors

First, excellent job with this project.

Sorry about the odd title.. hard to explain in few words. If you download the olson files right from the site, extract the entire download to a folder and then run the node_preparse.js script against it, you end up getting errors due to syntax issues. The two files that caused problems were the 'factory' file and the 'yearistype' shell script. I'm not really wanting to remember that I have to take those two files out each time that I run the script to add a timezone, so is there any way you can do sort of a 'pre-parse-check' to make sure that the file conforms to what the preparser is expecting?

Unhelpful error message if additional libraries (jQuery, Zepto) are not loaded

    if ((!fleegix || typeof fleegix.xhr === 'undefined') && typeof $.ajax === 'undefined') {
      throw new Error('Please use the Fleegix.js XHR module, jQuery ajax, Zepto ajax, or define your own transport mechanism for downloading zone files.');
    }

Here if additional libraries are not loaded $ is undefined and we try to get property of undefined which causes JavaScript error and we never get to the throw new Error part.
It should be

    if ((!fleegix || typeof fleegix.xhr === 'undefined') && (!$ || typeof $.ajax === 'undefined')) {

Arithmetic around DST results in incorrect times

Code

            console.log("Testing timezone-js dst transition...\n");
            var dt = new timezoneJS.Date(2006, 9, 29, 0, 59, 'America/Los_Angeles');
            console.log("12:59AM: " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));
            dt.setTime(dt.getTime() + (1 * 60 * 1000));
            console.log("Add 1 minute (First 1AM): " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));
            dt.setTime(dt.getTime() + (60 * 60 * 1000));
            console.log("Add 1 hour (Second 1AM): " + dt.toString("EEE, dd MMM yyyy HH:mm:ss Z"));

            console.log("\n\nTesting native dst transition...\n");
            var dt = new Date(2006, 9, 29, 0, 59);
            console.log("12:59AM: " + dt.toString());
            dt.setTime(dt.getTime() + (1 * 60 * 1000));
            console.log("Add 1 minute (First 1AM): " + dt.toString());
            dt.setTime(dt.getTime() + (60 * 60 * 1000));
            console.log("Add 1 hour (Second 1AM): " + dt.toString());

Output

Testing timezone-js dst transition...
12:59AM: Sun, 29 Oct 2006 00:59:00 PDT
Add 1 minute (First 1AM): Sun, 29 Oct 2006 01:00:00 PDT
Add 1 hour (Second 1AM): Sun, 29 Oct 2006 02:00:00 PST

Testing native dst transition...
12:59AM: Sun Oct 29 2006 00:59:00 GMT-0700 (Pacific Daylight Time)
Add 1 minute (First 1AM): Sun Oct 29 2006 01:00:00 GMT-0700 (Pacific Daylight Time)
Add 1 hour (Second 1AM): Sun Oct 29 2006 02:00:00 GMT-0700 (Pacific Daylight Time)

Upshot

The native date is more correct because although it doesn't have the correct time zone offset (says pacific daylight time instead of pacific standard time), the time that is outputted results in the correct point in time.

Timezone offsets negative

Aren't all the timezone offsets defined backwards?
If EST is 4 hours behind UTC shouldn't it be -240 rather than 240?

In other words shouldn't the getBasicOffset() negative sign on the return be removed?

clone doesn't copy tzInfo

When I clone a timezoneJS.Date object, everything seems to be copied except for tzInfo. Is this an oversight?

license missing

hi, I couln't find the license in the README or as a LICENSE file at the root of the project.

I see that the source code contains the Apache license header but it would be better to have it in the README and at the root of the project.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.