Cara menggunakan python datetime without timezone

First, let’s create a table and insert some events. We’ll insert the first event using a native time object, and the second with the

> r.table('events').filter(r.row['timestamp'].hours() > 20).run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

> r.table('events').filter(r.row['timestamp'].in_timezone('-02:00').hours() > 20).run(conn)
[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
7 constructor:

r.table_create('events').run(conn)

from datetime import datetime
r.table('events').insert([
    {'id': 0, 'timestamp': r.expr(datetime.now(r.make_timezone('-07:00')))},
    {'id': 1, 'timestamp': r.epoch_time(1376436769.923)}
]).run(conn)

Now, let’s get those back:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

You’ll notice that both times we inserted are returned as native Python

> r.table('events').filter(r.row['timestamp'].hours() > 20).run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

> r.table('events').filter(r.row['timestamp'].in_timezone('-02:00').hours() > 20).run(conn)
[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
8 objects. They’re in different time zones because
> r.table('events').filter(r.row['timestamp'].hours() > 20).run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

> r.table('events').filter(r.row['timestamp'].in_timezone('-02:00').hours() > 20).run(conn)
[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
9 requires us to specify a timezone, but
> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
0 creates a UTC time (it doesn’t know or care what time zone the client is in). In this example we’re using
> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
1, a ReQL helper command that only exists for Python, but you could use
> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
2 or another Python timezone library.

We can now filter based on these times:

> r.table('events').filter(r.row['timestamp'].hours() > 20).run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

> r.table('events').filter(r.row['timestamp'].in_timezone('-02:00').hours() > 20).run(conn)
[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

Or create a secondary index on them:

> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

Times are stored on the server as seconds since epoch (UTC) with millisecond precision plus a time zone. Currently the only available time zones are minute-precision time offsets from UTC, but we may add support for DST-aware time zones in the future. Time zones are strings as specified by ISO 8601.

Times are considered equal when their epoch (UTC) time values are equal, regardless of what time zone they’re in. This is true for both comparisons and indexed operations. Times are compared in floating point with millisecond precision.

Most date operations are only defined on years in the range

> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
3 (but note that times in the year
> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
4 cannot be printed as ISO 8601 dates).

Leap-seconds aren’t well-supported right now:

> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
5 and
> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
6 parse to the same time.

You can insert times by simply passing a Python

> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
7 object. Note that the Python driver requires
> r.table('events').filter(r.row['timestamp'].hours() > 20).run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]

> r.table('events').filter(r.row['timestamp'].in_timezone('-02:00').hours() > 20).run(conn)
[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
8 objects to have time zone information. (Most drivers will default to UTC if the object does not contain time zone information; for third party drivers, check their documentation.)

r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()

You can also use

> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
9 (which the server interprets as the time the query was received in UTC), or construct a time using
r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
0,
> r.table('events').index_create('timestamp').run(conn)
{'created': 1}
> r.table('events').between(r.epoch_time(1376436769.913),
                            r.epoch_time(1376436769.933),
                            index='timestamp').run(conn)
[{u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
0, or
r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
2.

> r.now().to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
> r.epoch_time(1376074395.012).to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.iso8601("2013-08-09T18:53:15.012-07:00").to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"

Times may be used as the primary key for a table. Two times are considered equal if they have the same number of milliseconds since epoch (UTC), regardless of time zone.

> r.table('t').insert(
      {'id': r.iso8601("2013-08-09T11:58:00.1111-07:00")}
  ).run(conn)
{'deleted': 0, 'errors': 0, 'inserted': 1, 'replaced:' 0, 'skipped': 0, 'unchanged': 0}

> r.table('t').insert(
      {'id': r.iso8601("2013-08-09T10:58:00.1112-08:00")}
  ).run(conn)
{'deleted': 0, 'errors': 1, 'inserted': 0, 'replaced:' 0, 'skipped': 0, 'unchanged': 0, 'first_error': 'Duplicate primary key `id`: ...'}

You may also insert a time by inserting a literal pseudotype object. This is useful if, for instance, you exported a row using

r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
3 (see Retrieving Times below).

Note: Avoid using keys matching the regular expression

r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
4 in your objects. RethinkDB considers those to be reserved keywords.

> r.expr({'$reql_type$': 'TIME',
          'epoch_time': 1376075362.662,
          'timezone': '+00:00'}).to_iso8601().run(conn)
"2013-08-09T19:09:22.662+00:00"

By default, times are converted into native time objects when they are retrieved from the server. This may be overridden by passing the optarg

r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
5 to
r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
6. The only options right now are
r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
7, the default, and
r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
8.

> r.now().run(conn)
datetime.datetime(2015, 2, 2, 19, 34, 10, 776000, tzinfo=)
> r.now().in_timezone('-07:00').run(conn)
datetime.datetime(2015, 2, 2, 12, 34, 55, 642000, tzinfo=)
> r.now().run(conn, time_format='raw')
{u'$reql_type$': u'TIME',
 u'epoch_time': 1422905756.693,
 u'timezone': u'-07:00'}

You can also transform a time object on the server using either

r.table('events').insert(
    {'id': 2, 'timestamp': datetime.now(r.make_timezone('00:00'))}
).run()
9 or
> r.now().to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
> r.epoch_time(1376074395.012).to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.iso8601("2013-08-09T18:53:15.012-07:00").to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
0.

> r.now().to_epoch_time().run(conn)
1376075986.574
> r.now().to_iso8601().run(conn)
"2013-08-09T19:19:46.574+00:00"

There are only three useful things you can do with a time: modify it, compare it to another time, or retrieve a portion of it.

You can put a time into a new time zone:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
0

You can also add or subtract a duration (in seconds):

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
1

If you subtract two times, you get a duration:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
2

All of the normal comparison operators are defined on times:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
3

Times are only compared with millisecond precision:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
4

There’s also the during command, which can check whether a time is in a particular range of times.

If you have a time, you can retrieve a particular portion (like the month, or the hours) relative to the current time zone. (See the full list at the API reference.)

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
5

We use the ISO 8601 definition of a week, which starts with Monday, represented as

> r.now().to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
> r.epoch_time(1376074395.012).to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.iso8601("2013-08-09T18:53:15.012-07:00").to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
1.

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
6

We define

> r.now().to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
> r.epoch_time(1376074395.012).to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.iso8601("2013-08-09T18:53:15.012-07:00").to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
2 and
> r.now().to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
> r.epoch_time(1376074395.012).to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.iso8601("2013-08-09T18:53:15.012-07:00").to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
3 for convenience:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
7

We also let you slice the time into the date and the current time of day (a time and a duration, respectively):

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
8

By combining these operations, you can write surprisingly useful queries in pure ReQL. For example, let’s say you have a table of sales your company has made, and you want to figure out how much of the gross comes from people who were working overtime:

> list(r.table('events').run(conn))

[{u'id': 0,
  u'timestamp': datetime.datetime(2015, 2, 2, 11, 56, 31, 250000, tzinfo=)},
 {u'id': 1,
  u'timestamp': datetime.datetime(2013, 8, 13, 23, 32, 49, 923000, tzinfo=)}]
9

If your timestamps are stored with time zones, this query will work even if you have sales from different offices in different countries (assuming they all work 9-5 local time).

Since this query is pure ReQL, the entire query will be distributed efficiently over the cluster without any computation being done on the client.

Further, because it’s ReQL, the query’s individual pieces are easily composable. If you decide you want those numbers on a per-month basis, you can just throw a

> r.now().to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.time(2013, r.august, 9, 18, 53, 15.012, '-07:00').to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
> r.epoch_time(1376074395.012).to_iso8601().run(conn)
"2013-08-09T18:53:15.012+00:00"
> r.iso8601("2013-08-09T18:53:15.012-07:00").to_iso8601().run(conn)
"2013-08-09T18:53:15.012-07:00"
4 in there: