5

我正在 Mongo db 中运行 map reduce 作业。

映射功能应该将某种性质的事件映射(例如计数)到某个时区的天数(映射的关键是日历日)。时区可以不同,实际上是 map/reduce 作业的输入参数。

存储在数据库对象中的时间采用 UTC。

例子:

object1: time=78000
object2: time=86420

mapReduce(objects, tz='America/Los_Angeles')
would return: [{"1/1/1970" : 2}]

mapReduce(objects, tz='Europe/London')
would return: [{"1/1/1970":1},{"1/2/1970":1}]

在同一个数据集上。

JavaScript Date 对象可以完美地将任何 UTC 时间转换为本地时间,但它似乎仅限于 J/S 环境的“当前”时区。我似乎找不到一种方法来指定我希望转换所在的时区。

转换应考虑 DST,最好考虑闰秒。

我能做些什么来实现这一目标吗?

4

1 回答 1

5

I found the answer that will work for me. The scope, after all, was limited to having this support in server-side mongo DB, and only on Linux.

@AsyaKamsky pointed to a greate J/S library, timezone-js, that does full and proper time zone support, considering that it uses actual time zone files from IANA. However, loading arbitrary java-script libraries into Mongo server environment is not that easy. You can only load global function definitions. timezone-js also needs to be provided with a custom transport mechanism to download the timezone files (I don't even know if MongoDB server environment provides files access), or the time zone files have to be precompiled into JSON objects, and served along with the library. I decided that this would be too tedious of an approach, and I will have to be responsible of providing mechanism to update time zone files when they are changed.

The other alternative I was looking into - is hacking the J/S implementation used in Mongo to add a function that will do the job I want it to do. That is what I have done. Things are actually as dismal in the world of glibc as they are in JavaScript, but there is a library for the job, icu.

I've made this patch, that adds a static Date.daytz() function, which, taken a UTC timestamp, and a time zone name, will return a yyyy-mm-dd string.

Considering the following map/reduce functions:

fmap = function () {
    emit(Date.daytz(this.time * 1000, globtz), {count:1});
};
fred = function (k, v) {
    var r = {count:0};
    v.forEach(function (v0) {r.count += v0.count;});
    return r;
};

I get exactly what I wanted, running these two map reduce commands:

{ "mapreduce" : "objects",
    "map" : fmap,
    "reduce" : fred,
    "out" : { "inline" : 1 },
    "scope" : { "globtz" : "Europe/London" } }

and

{ "mapreduce" : "objects",
    "map" : fmap,
    "reduce" : fred,
    "out" : { "inline" : 1 },
    "scope" : { "globtz" : "America/Los_Angeles" } }
于 2012-10-12T19:58:45.813 回答