bigeasy / timezone

Full-blown timezone aware date math and formatting for JavaScript in 2.7k.
http://bigeasy.github.io/timezone
MIT License
257 stars 27 forks source link

Release Timezone version 0.2.0. #41

Open bigeasy opened 12 years ago

bigeasy commented 12 years ago

I've created this issue for may many early adopters to be appraised of API changes to Timezone while it is on the 0.0.x version branch. Currently, I'm updating another issue to keep my many early adopters (and by many early adopters, I mean the very helpful @sberryman) appraised of such changes.

On the 0.0.x branch, API changes may break applications. Please use an absolute version number in your package.json to hold onto a version Timezone that works for you. When 0.0.x development is done, I'll create an 0.2.0 branch for application use and a 0.1.0 for any further development. The 0.2.0 branch will be an API freeze.

Timezone is stable at this point. There is only one API change to the Node.js API remaining; I'm going to move the zone database somewhere, so you're require will have to change. Otherwise, the invocation of the tz function is highly unlikely to change.

There will be further development to Timezone to make it work well in the browser, but that is unlikely to affect Node.js users.

Thank you very much for using Timezone.

sberryman commented 12 years ago

Sounds great!

bigeasy commented 12 years ago

I've published version 0.0.12 to NPM. This includes a major change to the layout of resources and therefore the API.

Timezone and locale data is now in the root of the project directory structure.

var tz = require("timezone");
de = tz(require("timezone/Europe"), require("timezone/de_DE"));
console.log(de(0, "Europe/Berlin", "de_DE", "%c"));

The above program will print.

$ node de.js
Do 01 Jan 1970 01:00:00 CET

You'll notice that we're now saying "timezone/Europe" instead of "timezone/zones/Europe" and "timezone/de_DE" instead of "timezone/locales/de_DE".

This is probably the last major API change before 0.2.0 and certainly the last change to the package structure, so feel free to make the transition to 0.0.12, your changes won't be undone.


Timezone 0.0.12

Timezone aware date formatting and date math for Node.js.

timezone.js is 2.85k minified and gzipped for use in the browser via RequrieJS AMD or just drop it in.

Changes for 0.0.12

bigeasy commented 12 years ago

My apologies for version 0.0.13 just published to NPM. It is not intended for use, but for posterity. It finishes up some of the details of the API, but it took a wrong direction on date arrays. If you're using date arrays, do not use this version.

I created a release for my own sake, to remind myself why I didn't do the things I did in this release.

A version 0.0.14 is coming soon that will even this all out. Release 0.0.12 is really solid, so stick with that.


timezone.js is now a gargantuan 2.98k minified and gizpped.

Changes for 0.0.13.

sberryman commented 12 years ago

Thanks, I'll make the change to 0.0.12 tomorrow and let you know how it goes

On Jun 25, 2012, at 7:23 AM, Alan Gutierrez < reply@reply.github.com> wrote:

My apologies for version 0.0.13 just published to NPM. It is not intended for use, but for posterity. It finishes up some of the details of the API, but it took a wrong direction on date arrays. If you're using date arrays, do not use this version.

I created a release for my own sake, to remind myself why I didn't do the things I did in this release.

A version 0.0.14 is coming soon that will even this all out. Release 0.0.12 is really solid, so stick with that.


timezone.js is now a gargantuan 2.98k minified and gizpped.

Changes for 0.0.13.


Reply to this email directly or view it on GitHub: https://github.com/bigeasy/timezone/issues/41#issuecomment-6544916

bigeasy commented 12 years ago

Back on track with version 0.0.14 no available on NPM. If you're going to update soon, please use this version.

Timezone is now 2.75k minified and gzipped. For Node.js users I've created a module called loaded.js so you can...

var tz = require("timezone/loaded");
console.log(tz(0, "Europe/Paris", "fr_FR", "%c"));

And you'll get...

$ node fr.js 
jeu. 01 janv. 1970 01:00:00 CET

You can build dates from arrays of date fields again, with one based months. The Timezone function will flatten all other arrays, so you can build an argument array programmatically and pass it to Timezone without using Function.apply.


Back down to 2.75k.

Changes for 0.0.14.

sberryman commented 12 years ago

Sorry, I've been swamped recently and now we've got a holiday "week"

I'll try and get to this early next week, any new changes or should I wait until 0.2?

bigeasy commented 12 years ago

Please go ahead. Everything is stable. All of the issues in the issue tracker relate to the GitHub:Pages site I'm creating.

The only API question I'm wrestling with is whether to keep "*" to mean "now" and set it using a configurable clock function. If you have an opinion on this, please let me know in #80. If you don't, then it won't effect your code.

It would be great to get feedback on 0.0.14, so thank you.

sberryman commented 12 years ago

Excellent, just as a heads up. This is probably my favorite documentation layout for an opensource project: http://momentjs.com/

sberryman commented 12 years ago

FYI, I never knew about * but something I have found myself doing quite a bit of is finding the start of day in a timezone. I've been doing it like this, is there an easier way?

sod = tz("*", 'America/Los_Angeles', '%Y-%m-%d')
sod = tz(sod, 'America/Los_Angeles')
sberryman commented 12 years ago

Everything is working great with 0.0.14 by the way

bigeasy commented 12 years ago

Actually, that's what I humbly consider the exact right way to do it. It will always be correct.

It follows the rules of first converting to wall-clock time, then working with wall-clock time as a string. I plan on adding exactly this example to the functional composition section of the documentation.

When considering how to do rounding, I did consider extending formats or adding math commands, but nothing occurred to me that wasn't as obvious and logical as this. It would be doing exactly this behind the scenes.

You can, of course, create a partial function around "America/Los_Angeles", which makes

var la = tz('America/Los_Angeles')
  , sod;

sod = la(la("*", '%Y-%m-%d'));

When you create a locally configured tz function, the functional composition DRYs up quite a bit.

sberryman commented 12 years ago

It was actually a really simple upgrade. All I had to do was replace all tz() with '*'

On Mon, Jul 9, 2012 at 9:06 AM, Alan Gutierrez < reply@reply.github.com

wrote:

Actually, that's what I humbly consider the exact right way to do it. It will always be correct.

It follows the rules of first converting to wall-clock time, then working with wall-clock time as a string. I plan on adding exactly this example to the functional composition section of the documentation.

When considering how to do rounding, I did consider extending formats or adding math commands, but nothing occurred to me that wasn't as obvious and logical as this. It would be doing exactly this behind the scenes.

You can, of course, create a partial function around "America/Los_Angeles", which makes

var la = tz('America/Los_Angeles')
  , sod;

sod = la(la("*", '%Y-%m-%d'));

When you create a locally configured tz function, the functional composition DRYs up quite a bit.


Reply to this email directly or view it on GitHub: https://github.com/bigeasy/timezone/issues/41#issuecomment-6851078

sberryman commented 12 years ago

How do I use this in the browser? I am deperate to replace all the hacks I have client side. I don't care how big the file is and wouldn't mind loading the entire timezone library.

bigeasy commented 12 years ago

Askshoelly... The minified and gzipped size of the library is 2.66k on master. It's always been less than 3k.

All of the zone files mashed into one file 61.76k zipped, while America is 22.42k. You can load a zone a time, a continent at a time, or all at once. I've broken them up and they are hosted on GitHub:Pages and available as a zip for you to host.

All of the v0.0.14 files are available on GitHub:Pages as JSON, AMD and JSONP. Here are links to America/Detroit.

http://bigeasy.github.com/timezone/v0.0.14/amd/America/Detroit.js http://bigeasy.github.com/timezone/v0.0.14/jsonp/America/Detroit.js http://bigeasy.github.com/timezone/v0.0.14/json/America/Detroit.js

As a change in v0.0.15, the json file extension will become .json. but for now it is .js. You probably can't use JSON from GitHub:Pages, but you can use JSONP or AMD.

You can use the GitHub:Pages files or download the files as a zip. Put JSON on your own site and use it there.

https://github.com/bigeasy/timezone/tags

The data files in that directory will be the data files for each version.

I'm able to help you step by step. Let me know which way you want to go. I'm sorry but I'm working on another project this week. I'd plan on having a nice GitHub:Pages site with documentation on web usage and web examples for next week.

Here is a completely rudimentary start of an AMD based example page. (Rudimentary!)

http://bigeasy.github.com/timezone/amd.html https://github.com/bigeasy/timezone/blob/gh-pages/scripts/main.js

Let me know which path you want to take. I can scratch out some examples for you because I'll use them in the docco site anyway.

TL;DR

Get the Zones into your browser as a JavaScript object and make a tz function that contains them: Bada bing!

sberryman commented 12 years ago

Sweet! I'll start working on replacing all my hacks client side, I can't wait to get rid of that crap! Should I post any questions I have on github or do you want me to email you?

bigeasy commented 12 years ago

Please put questions here. It will encourage others to ask questions here. This is kind of functioning as discussion board lite. Please don't hesitate to ask questions. Feedback on web use would be great.

sberryman commented 12 years ago

"Get the Zones into your browser as a JavaScript object and make a tz function that contains them"

So I can pass in the entire list of zones to tz but then it has to lookup the zone from the array each time. How could I avoid this by parsing it once per timezone?

For example, my app deals with golf courses all over the world. The user doesn't change to courses in other time zones very often but it does happen. When they switch I would like to be able to lookup the zone once and store it as part of the model client side. That way it will make the tz function MUCH MUCH faster as it doesn't have to lookup the zone from the massive array of all the zones every time.

sberryman commented 12 years ago

Nevermind, I just used your example from 5 days ago: la = tz('America/Los_Angeles')

bigeasy commented 12 years ago

@sberryman Yes. That's the way to reduce parameters to tz, create a partial that names the settings you'll use for a series of calculations. You can do something like z = tz('Europe/Berlin', 'de_DE'), and then the z function can be used to show dates to Berliners with z('*', '%c').

As far as having the whole set of timezones enclosed in tz. It's not that big of a lookup. It first looks up the zone using the zone name, the zone set is a skip list skip list skewed toward the present, so the rules for today's date are often found in the first entry.

Thus, loading one zone set or all zone sets won't effect offset calculation time. The only real cost is the size of the download to the browser.

In Node.js you can use require('tz/loaded') to get a tz function loaded with the entire database and ready to go. I'd say this is the best way to use it in Node.js. The size of the database is going to be trivial on a production server.

bigeasy commented 12 years ago

Also, if you do find tz to be slow for some reason, let me know. I'd planned on focusing on optimizing after 0.2.0, but I did some testing and found formatting performance to be comparable to timezone-unaware JavaScript libraries.

Hope I'm addressing your concerns. Please feel free to ask any questions.

sberryman commented 12 years ago

@bigeasy thanks for the quick response. I'm using tz/loaded already server side. The partial sped up the the formatting quite a bit, knocked off about 150ms. I am formatting about 190-200 times per page and the performance is exactly like you have mentioned, the same as timezone-unaware libraries (same as momentjs which I was using)

It was actually a very easy migration and have it fully working after a few hours on a separate branch. It feels great to get rid of all the other libraries I was "trying" to use to get around timezone issues. Now I'll probably take the time to implement requirejs so I don't have to load the entire dataset.

Thanks again!

sberryman commented 12 years ago

It doesn't appear to work when creating a partial that includes the locale. I tried fr = tz('America/Detroit', 'fr_FR') and then fr('*', '%A') and it seems to default to 'en_US'. Is this the expected behavior?

bigeasy commented 12 years ago

Nope. Checking.

sberryman commented 12 years ago

don't waste your time, turns out I was passing an object as the locale NOT a string

bigeasy commented 12 years ago

@sberryman Okay. So, I assume you're specifying a locale by string, creating a Timezone function that has enclosed those settings. However, you probably didn't create a Timezone function that encloses the locale data structure.

var tz = require('timezone');

var loaded = tz(require('timezone/fr_FR'), require('timezone/America/Detroit'));

var fr = loaded('America/Detroit', 'fr_FR');

console.log(fr('*', '%c'));

https://gist.github.com/3124426

In Node.js you might require('tz/loaded') which takes care of loading all the locales and zones.

bigeasy commented 12 years ago

Okay. Great. Thank you for the continued feedback.

sberryman commented 12 years ago

now comes the question, how can I help with locales and is there any type of fallback. For example, in en_US there is time12 and time24. However, those do not exist in other locales (for good reason of course)

bigeasy commented 12 years ago

What locales to you need now? Give me a list and I'll get them built. I'll try to do as many as I can, but want to make sure I get the ones you need. Try to have this done tomorrow. See #116.

Timezone implements strftime, which is the date format language for Perl, Ruby, Python, Lua and C. It is the format language used by GNU date. So, it provides formats like %c which is a localized time and date format. I chose to implement strftime, with all the GNU extensions, so that I could point to a standard.

If you do not like %c, than maybe we should work out some alternates. I can have a look on the Internet to see what others have done.

I find %c to be a bit too chatty. I believe that '%x %X' does a pretty good job most of the time.

$ date +'%x %X'
07/16/2012 03:28:59 PM
% LANG=en_GB.UTF-8 date +'%x %X'
16/07/12 15:29:58

Let me know what you're thinking, what problems you're having with localization.

sberryman commented 12 years ago

I really like how Microsoft and Java have done date formats with FULL, LONG, MEDIUM and SHORT

Java: http://docs.oracle.com/javase/1.4.2/docs/api/java/text/DateFormat.html Microsoft.NET: http://msdn.microsoft.com/en-us/library/az4se3k1.aspx

The only one I really need is es_ES. I'm new to this whole localization field so forgive me if I am asking stupid questions.

bigeasy commented 12 years ago

Reminder to self that Timezone needs to be listed in MicroJS and Jam.

bigeasy commented 12 years ago

Also, way behind on getting es_ES done. Sorry.

sberryman commented 12 years ago

I'll submit a pull request with the data from jquery for this today

bigeasy commented 12 years ago

Oh, sorry. I'm just about done with this. Have a few more locales done.

sberryman commented 12 years ago

I was going to write a quick script to parse all the jquery translations. Maybe .NET or Java implementations would be a better source?

bigeasy commented 12 years ago

The format language is strftime, so it is the exact same language as the one found in the GNU date utility. There's not that much need for parsing other formats.

bigeasy commented 12 years ago

Ugh. That didn't sound right. Let me try again when I get this commit done.

sberryman commented 12 years ago

Haha, I was talking about a way to import the translations other people have done for other projects.

Example: http://jquery-ui.googlecode.com/svn/trunk/ui/i18n/

sberryman commented 12 years ago

haha, now that is a nice commit!

bigeasy commented 12 years ago

@sberryman I think the problem with the UNIX style date formats is that the long version shows the time zone abbreviation, which is silly for most applications.

sberryman commented 12 years ago

Agree, I really like the Java and .NET short, medium and long formats. Have you thought about ways to incorporate those?

On Wed, Jul 18, 2012 at 2:48 PM, Alan Gutierrez < reply@reply.github.com

wrote:

@sberryman I think the problem with the UNIX style date formats is that the long version shows the time zone abbreviation, which is silly for most applications.


Reply to this email directly or view it on GitHub: https://github.com/bigeasy/timezone/issues/41#issuecomment-7083322

bigeasy commented 12 years ago

You can use this function, lfmt to take a locales long format and remove seconds and timezone abbreviation, which creates a not-so-terribly-long long format.

var tz = require('timezone/loaded') ;

console.log(tz('*', lfmt(tz, 'fr_FR'), 'America/Montreal'));

function lfmt (tz, locale) {
  return [ locale, tz(function () { return this[locale].dateTime.replace(/%Z|[:.]%S/g, '').trim() }) ];
}

Running above gives.

$ node example.js
mer. 18 juil. 2012 17:51

Using a partial.

var tz = require('timezone/loaded') ;
var qc = tz('America/Montreal', lfmt(tz, 'fr_FR'));

console.log(qc('*'));
console.log(qc('*', '%c')); // override format

function lfmt (tz, locale) {
  return [ locale, tz(function () { return this[locale].dateTime.replace(/%Z|[:.]%S/g, '').trim() }) ];
}

Output.

$ node example.js
mer. 18 juil. 2012 17:59
mer. 18 juil. 2012 17:59:25 EDT

Could you make use of this?

sberryman commented 12 years ago

I really needed the short, medium, long date AND a short, medium and long time. My product is doing reservations and I need to separate out the date and time in most cases.

bigeasy commented 12 years ago

What I did today was trace the locale information in strftime back to its source. I've been able to generate locales using the intermate formats used by GNU and Apache. Here's an example file.

http://svn.apache.org/repos/asf/stdcxx/trunk/etc/nls/src/ms_MY

From these files I can get the correct strftime patterns. That's done.

While looking at the sources of localization data, I found that GLIBC does act as a original source with original research, like the Olson database. It draws information from earlier efforts I've yet to identify. It is also beginning to reconcile itself with ICU CLDR, the Common Locale Data Repository from the International Components for Unicode.

http://cldr.unicode.org/http://cldr.unicode.org/index/downloads

The "short, medium, long date AND a short, medium and long time" format information found in .NET and Java almost certainly comes from formats defined in the CLDR. The GNU Java compiler uses CLDR to implement localization including date format.

Implementing the format smorgasbord would be a matter of weeding through the XML source with jindw/xmldom (I've got no problem with XML) and converting them into strftime formats. API is probably a new kind of string you can pass to the Timezone function, "--long-date-format".

I'm happy that this conversation lead me to find another standards body. I wasn't looking forward to piecing together date formats from sundry repos on GitHub.

TL;DR

Found those formats you were looking for and then some in a great big standardized database of original research, but I'll need some time to build a to-JSON converter.

I can hand code the ones you need for now. I believe you need fr_FR, de_DE, es_ES, en_US, en_GB for your product ASAP. Anything else that needs to be on the short list? I'll hand code a few to sort out the API.

sberryman commented 12 years ago

Those are it but no rush, honestly. I was planning on hand coding the formats in my app until you had the time to do it. Those language sites get VERY VERY little use right now. I was just planning on getting a sales person in Spain to start ramping up and wanted the core European languages.

On Wed, Jul 18, 2012 at 7:34 PM, Alan Gutierrez < reply@reply.github.com

wrote:

What I did today was trace the locale information in strftime back to its source. I've been able to generate locales using the intermate formats used by GNU and Apache. Here's an example file.

http://svn.apache.org/repos/asf/stdcxx/trunk/etc/nls/src/ms_MY

From these files I can get the correct strftime patterns. That's done.

While looking at the sources of localization data, I found that GLIBC does act as a original source with original research, like the Olson database. It draws information from earlier efforts I've yet to identify. It is also beginning to reconcile itself with ICU CLDR, the Common Locale Data Repository from the International Components for Unicode.

http://cldr.unicode.org/http://cldr.unicode.org/index/downloads

The "short, medium, long date AND a short, medium and long time" format information found in .NET and Java almost certainly comes from formats defined in the CLDR. The GNU Java compiler uses CLDR to implement localization including date format.

Implementing the format smorgasbord would be a matter of weeding through the XML source with jindw/xmldom (I've got no problem with XML) and converting them into strftime formats. API is probably a new kind of string you can pass to the Timezone function, "--long-date-format".

I'm happy that this search lead me to find another standards body. I wasn't looking forward to piecing together date formats from sundry repos on GitHub.

TL;DR

Found those formats you were looking for and then some in a great big standardized database of original research, but I'll need some time to build a to-JSON converter.

I can hand code the ones you need for now. I believe you need fr_FR, de_DE, es_ES, en_US, en_GB for your product ASAP. Anything else that needs to be on the short list? I'll hand code a few to sort out the API.


Reply to this email directly or view it on GitHub: https://github.com/bigeasy/timezone/issues/41#issuecomment-7088332

pivotaltracker commented 12 years ago

Thanks, this is a great looking library. We want to use it in a browser without require.js. About a month ago, you wrote that "I'd plan on having a nice GitHub:Pages site with documentation on web usage and web examples for next week." Do you have those page up somewhere? Do you have an idea when the updates to the code to make it easier to use in a browser will be ready? Many thanks again, Sanford

bigeasy commented 12 years ago

@pivotaltracker It is actually quite easy to use in the browser right now using AMD or just including the files using script tags. I'm somewhat focused on another personal project at the moment, so give a day to sort out a time when I can come back to timezone. In the mean time, if you have any specific questions let me know. It will work great it the browser right now.

pivotaltracker commented 12 years ago

We found it effortful to do the include steps by hand and didn't want to use AMD for size reasons. We modified the mde/timezone.js to work for the moment but I really like yours. If you do have time to set it up to be easy to use in the browser without AMD, that would be awesome for lots of people. It's a great library. No hurry for us, though. Thanks again.

bigeasy commented 11 years ago

Updated to use IANA TZ Database tz2013d which was released July 5th. See #166.