Spec-Zone.ru › RethinkDB javascript

Даты и время в RethinkDB

RethinkDB имеет встроенную поддержку времени с точностью до миллисекунды и часовыми поясами. Некоторые моменты:

  • Время интегрировано с официальными драйверами, которые автоматически преобразуют его в и из типов времени, используемых в вашем языке.
  • Запросы учитывают часовой пояс, поэтому вы можете задавать вопросы, такие как: «Произошло ли это событие в понедельник в часовом поясе, где оно было записано?»
  • Время используется в качестве индексов, поэтому вы можете эффективно извлекать события на основе времени их возникновения.
  • Операции со временем являются чистыми ReQL-операциями, что означает, что даже сложные запросы с датами и временем могут быть эффективно распределены по кластеру.
  • Быстрый пример
  • Технические детали
  • Вставка времени
  • Извлечение времени
  • Работа со временем
  • Всё вместе

Dates and Times Illustration

Быстрый пример

Сначала создадим таблицу и вставим некоторые события. Первое событие мы вставим с помощью объекта Date, а второе — с помощью конструктора epochTime:

r.tableCreate('events').run(conn, callback);

r.table('events').insert([
    {id: 0, timestamp: new Date()},
    {id: 1, timestamp: r.epochTime(1376436769.923)}
]).run(conn, callback);

Теперь извлечём их:

> r.table('events');
// Result passed to callback
[
    { "id": 0, "timestamp": Date("2013-08-13T23:32:49.923Z") },
    { "id": 1, "timestamp": Date("2013-08-13T23:32:49.923Z") }
]

Вы заметите, что оба вставленных времени возвращаются как родные JavaScript-объекты Date. (Объекты Date не хранят информацию о часовом поясе, поэтому оба времени являются UTC, независимо от часового пояса вашего сервера.)

Теперь мы можем фильтровать по этим временным меткам:

> r.table('events').filter(r.row('timestamp').hours().gt(20)).run(conn, callback);
// Result passed to callback
[ { "id": 1, "timestamp": Date("2013-08-13T23:32:49.923Z") } ]

Или создать дополнительный индекс на них:

> r.table('events').indexCreate('timestamp').run(conn, callback);

> r.table('events').between(r.epochTime(1376436769.913),
      r.epochTime(1376436769.933), {index: 'timestamp'}
  ).run(conn, callback);
// Result passed to callback
[ { "id": 1, "timestamp": Date("2013-08-13T23:32:49.923Z") } ]

Технические детали

Время хранится на сервере как количество секунд с эпохи (UTC) с точностью до миллисекунды плюс часовой пояс. В настоящее время доступны только часовые пояса — смещения от UTC с точностью до минуты, но в будущем мы можем добавить поддержку часовых поясов, учитывающих переходы на летнее время. Часовые пояса представлены строками в формате ISO

  1. Обратите внимание, что драйвер JavaScript удаляет информацию о часовом поясе из-за ограничений объекта Date, хотя вы можете получить данные о часовом поясе через объект времени ReQL. (См. ниже.)

Время считается равным, когда значения времени эпохи (UTC) равны, независимо от часового пояса. Это верно как для сравнений, так и для индексированных операций. Время сравнивается с плавающей точкой с точностью до миллисекунды.

Большинство операций с датой определены только для годов в диапазоне [1400, 10000] (но обратите внимание, что время в году 10000 не может быть выведено как дата ISO 8601).

Секунды високосного времени в настоящее время не полностью поддерживаются: 2012-06-30T23:59:60 и 2012-07-01T00:00:00 интерпретируются как одно и то же время.

Вставка времени

Вы можете вставлять время, просто передав объект Date.

> r.table('events').insert({id: 2, timestamp: new Date()}).run(conn, callback);
// Result passed to callback
{"unchanged"=>0, "skipped"=>0, "replaced"=>0, "inserted"=>1, "errors"=>0, "deleted"=>0}

Вы также можете использовать r.now (которое сервер интерпретирует как время получения запроса в UTC), или построить время, используя r.time, r.epochTime, или r.ISO8601.

> r.now().toISO8601().run(conn, callback);
// Result passed to callback
"2013-08-09T18:53:15.012+00:00"

> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').toISO8601().run(conn, callback);
// Result passed to callback
"2013-08-09T18:53:15.012-07:00"

> r.epochTime(1376074395.012).toISO8601().run(conn, callback);
// Result passed to callback
"2013-08-09T18:53:15.012+00:00"

> r.ISO8601("2013-08-09T18:53:15.012-07:00").toISO8601().run(conn, callback);
// Result passed to callback
"2013-08-09T18:53:15.012-07:00"

Время может быть использовано в качестве первичного ключа для таблицы. Два времени считаются равными, если у них одинаковое количество миллисекунд с эпохи (UTC), независимо от часового пояса.

> r.table('t').insert(
      {id: r.ISO8601("2013-08-09T11:58:00.1111-07:00")}
  ).run(conn, callback);
// Result passed to callback
{"unchanged"=>0, "skipped"=>0, "replaced"=>0, "inserted"=>1, "errors"=>0, "deleted"=>0}

> r.table('t').insert(
      {id: r.ISO8601("2013-08-09T10:58:00.1111-08:00")}
  ).run(conn, callback);
// Result passed to callback
{"unchanged"=>0, "skipped"=>0, "replaced"=>0, "inserted"=>0,
 "first_error"=>"Duplicate primary key `id`: ...", "errors"=>1, "deleted"=>0}

Также можно вставить время, вставив объект-литерал псевдотипа. Это полезно, если, например, вы экспортировали строку с использованием {timeFormat: 'raw'} (см. Извлечение времени ниже).

Примечание: Избегайте использования ключей, соответствующих регулярному выражению ^\$reql_.+\$$ в ваших объектах. RethinkDB рассматривает их как зарезервированные ключевые слова.

> r.expr(
      {'$reql_type$': 'TIME', epoch_time: 1376075362.662, timezone: '+00:00'}
  ).run(conn, callback);
// Result passed to callback
Date("2013-08-09T19:09:22.662Z")

Извлечение времени

По умолчанию время преобразуется в объекты времени при извлечении с сервера. Это можно изменить, передав параметр timeFormat в run. На данный момент доступны только native, по умолчанию, и raw. Обратитесь к ссылке на API, если у вас есть вопросы о передаче необязательных аргументов в JavaScript.

> r.now().run(conn, callback);
// Result passed to callback
Date("2013-08-13T23:32:49.923Z")

> r.now().inTimezone('-07:00').run(conn, callback);
// Result passed to callback: same as above, no TZ info retrieved
Date("2013-08-13T23:32:49.923Z")

> r.now().run(conn, {timeFormat: 'raw'}, callback);
// Result passed to callback
{
  "$reql_type$": "TIME",
  "epoch_time": 1423077622.659,
  "timezone": "+00:00"
}

> r.now().inTimezone('-07:00').run(conn, {timeFormat: 'raw'}, callback);
// Result passed to callback, now with TZ info
{
  "$reql_type$": "TIME",
  "epoch_time": 1423077646.772,
  "timezone": "-07:00"
}

Вы также можете преобразовать объект времени на сервере, используя toEpochTime или toISO8601.

> r.now().toEpochTime().run(conn, callback);
// Result passed to callback
1376075986.574

> r.now().toISO8601().run(conn, callback);
// Result passed to callback
"2013-08-09T19:19:46.574+00:00"

Работа со временем

Есть только три полезных действия с временем: изменить его, сравнить его с другим временем или получить часть из него.

Изменение времени

Вы можете добавить или вычесть длительность (в секундах):

> r.time(2015, 1, 1, 'Z').add(86400).run(conn, callback);
// Result passed to callback
Fri Jan 02 2015 00:00:00 GMT+00:00

Если вы вычитаете две временные метки, вы получите длительность:

> r.time(2015, 1, 2, 'Z').sub(r.time(2015, 1, 1, 'Z')).run(conn, callback);
// Result passed to callback
86400

Сравнение времени

Определены все стандартные операторы сравнения:

> r.epochTime(1376081287.982).lt(new Date()).run(conn, callback);
true

Время сравнивается только с точностью до миллисекунды:

> r.epochTime(1376081287.9821).eq(r.epochTime(1376081287.9822)).run(conn, callback);
true

Также есть команда during, которая может проверить, находится ли время в определенном диапазоне.

Получение частей времени

Если у вас есть время, вы можете получить определённую часть (например, месяц или часы) относительно текущего часового пояса. (См. полный список в ссылке на API.)

> r.expr(new Date()).run(conn, callback);
// Result passed to callback
"2013-08-13T23:32:49.923Z"

> r.expr(new Date()).month().run(conn, callback);
// Result passed to callback
8

> r.expr(new Date()).hours().run(conn, callback);
// Result passed to callback
23

> r.expr(new Date()).inTimezone('-06:00').hours().run(conn, callback);
// Result passed to callback
17

Мы используем определение недели ISO 8601, которая начинается с понедельника, представленного как 1.

> r.expr(new Date()).dayOfWeek().run(conn, callback);
5 # Friday

Мы определяем r.monday...r.sunday и r.january...r.december для удобства:

> r.expr(new Date()).dayOfWeek().eq(r.friday).run(conn, callback);
true

Мы также позволяем вам разбить время на дату и текущее время суток (время и продолжительность соответственно):

> r.now().toEpochTime().run(conn, callback);
// Result passed to callback
1376351312.744

> r.now().date().toEpochTime().run(conn, callback);
// Result passed to callback
1376265600

> r.now().timeOfDay().run(conn, callback);
// Result passed to callback
85712.744

Всё вместе

Комбинируя эти операции, можно писать довольно полезные запросы в чистом ReQL. Например, предположим, у вас есть таблица продаж, сделанных вашей компанией, и вы хотите узнать, сколько прибыли принесли люди, работавшие сверхурочно:

r.table('sales').filter(function (sale) {
    // Weekends are overtime
    return sale('time').dayOfWeek().eq(r.saturday).or(
        sale('time').dayOfWeek().eq(r.sunday)).or(
        // Weekdays outside 9-5 are overtime
        sale('time').hours().lt(9)).or(
        sale('time').hours().ge(17));
}).sum('dollars').run(conn, callback);

Если ваши временные метки хранятся с часовыми поясами, этот запрос будет работать даже если у вас есть продажи из разных офисов в разных странах (при условии, что все они работают с 9 до 17 по местному времени).

Поскольку этот запрос является чистым ReQL, весь запрос будет эффективно распределён по кластеру без каких-либо вычислений на клиенте.

Кроме того, поскольку это ReQL, отдельные части запроса легко объединяются. Если вы решите, что вам нужно эти цифры по месяцам, вы можете добавить group:

r.table('sales').filter(function (sale) {
    // Weekends are overtime
    return sale('time').dayOfWeek().eq(r.saturday).or(
        sale('time').dayOfWeek().eq(r.sunday)).or(
        // Weekdays outside 9-5 are overtime
        sale('time').hours().lt(9)).or(
        sale('time').hours().ge(17));
}).group(function (sale) {
    return sale('time').month();
}).sum('dollars').run(conn, callback);

© RethinkDB contributors
Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
https://rethinkdb.com/docs/dates-and-times/javascript/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API