NAME
PDL::DateTime - A piddle for keeping high precision (microsecond) timestamps
DESCRIPTION
PDL::DateTime is a subclass of PDL piddle for storing date-time values (scalar piddles, vectors, matrices or generally ND-piddles):
its PDL type is always
LongLong
(64-bit signed integer)stored values are microseconds since
1970-01-01T00:00:00.000000Z
(can be both positive or negative)it is still a piddle so you can do all usual PDL arithmetic + PDL::DateTime defines some new methods (see below)
LIMITATIONS
supported datetimes are from
0001-01-01T00:00:00.000000Z
(epoch microseconds:-62135596800000000
) to9999-12-31T23:59:59.999999Z
(epoch microseconds:253402300799999999
)leap seconds are completely ignored
no timezone handling (module uses GMT, date time values without offset/timezone are considered to be GMT)
this module works only on perls with 64-bit integers, check
perl -V:ivsize
(should beivsize='8'
)no chance for nanoseconds precision, maybe in a separate module e.g.
PDL::DateTime::Ns
SYNOPSIS
use
5.010;
use
PDL;
use
PDL::DateTime;
my
$dt_1
= PDL::DateTime->new_sequence(
'2015-09-20T15:45'
, 5,
'hour'
);
say
$dt_1
;
# [ 2015-09-20T15:45 2015-09-20T16:45 2015-09-20T17:45 2015-09-20T18:45 2015-09-20T19:45 ]
say
$dt_1
->where(
$dt_1
>
'2015-09-20T17:00'
);
# [ 2015-09-20T17:45 2015-09-20T18:45 2015-09-20T19:45 ]
say
$dt_1
->dt_hour;
# [15 16 17 18 19]
say
$dt_1
->dt_minute;
# [45 45 45 45 45]
say
$dt_1
->dt_add(
year
=> 4,
month
=>6,
day
=>3);
# [ 2020-03-23T15:45 2020-03-23T16:45 2020-03-23T17:45 2020-03-23T18:45 2020-03-23T19:45 ]
my
$dt_2
= PDL::DateTime->new_sequence(
'2015-11-22T23:23:23.654321'
, 4,
'day'
);
say
$dt_2
;
# [ 2015-11-22T23:23:23.654321 2015-11-23T23:23:23.654321 2015-11-24T23:23:23.654321 2015-11-25T23:23:23.654321 ]
say
$dt_2
->dt_align(
'day'
);
# [ 2015-11-22 2015-11-23 2015-11-24 2015-11-25 ]
say
$dt_2
->dt_align(
'hour'
);
# [ 2015-11-22T23:00 2015-11-23T23:00 2015-11-24T23:00 2015-11-25T23:00 ]
say
$dt_2
->dt_align(
'minute'
);
# [ 2015-11-22T23:23 2015-11-23T23:23 2015-11-24T23:23 2015-11-25T23:23 ]
FUNCTIONS
new
my
$p
= PDL::DateTime->new(
$pdl_or_array_ref
);
# input data = microseconds (LongLong) since 1970-01-01T00:00:00Z (positive or negative)
# input data are always converted to LongLong
new_from_epoch
my
$p
= PDL::DateTime->new_from_epoch(
$pdl_or_array_ref
);
# BEWARE: precision in miliseconds only!
# input data = seconds (int or double) since 1970-01-01T00:00:00Z (positive or negative)
new_from_ratadie
my
$p
= PDL::DateTime->new_from_ratadie(
$pdl_or_array_ref
);
# BEWARE: precision in miliseconds only!
# input data = days (int or double) since January 1, 0001 AD 00:00
See https://en.wikipedia.org/wiki/Rata_Die
new_from_serialdate
my
$p
= PDL::DateTime->new_from_serialdate(
$pdl_or_array_ref
);
# BEWARE: precision in miliseconds only!
# input data = days (int or double) since January 1, 0000 AD 00:00
See http://www.mathworks.com/help/finance/handling-and-converting-dates.html
new_from_juliandate
my
$p
= PDL::DateTime->new_from_juliandate(
$pdl_or_array_ref
);
# BEWARE: precision in miliseconds only!
# input data = days (int or double) since November 24, 4714 BC 12:00
See https://en.wikipedia.org/wiki/Julian_day
new_from_datetime
my
$p
= PDL::DateTime->new_from_datetime(
$array_ref
);
# input data = array of ISO 8601 date time strings
my
$dt
= PDL::DateTime->new_from_datetime([
[
'2015-09-20T15:45'
,
'2015-09-20T16:45'
,
'2015-09-20T17:45'
],
[
'2016-09-20T15:45'
,
'2016-09-20T16:45'
,
'2016-09-20T17:45'
],
[
'2017-09-20T15:45'
,
'2017-09-20T16:45'
,
'2017-09-20T17:45'
],
]);
Supported formats - see Time::Moment.
new_from_parts
my
$p
= PDL::DateTime->new_from_parts(
$y
,
$m
,
$d
,
$H
,
$M
,
$S
,
$U
);
# all arguments are either piddles or array refs
# $y .. years (1..9999)
# $m .. months (1..12)
# $d .. days (1..31)
# $H .. hours (0..23)
# $M .. minutes (0..59)
# $S .. seconds (0..59)
# $U .. microseconds (0..999999)
new_from_ymd
my
$p
= PDL::DateTime->new_from_ymd(
$ymd
);
# BEWARE: handles only dates!
# $ymd (piddle or array ref) with dates like:
# [ 20150831, 20150901, 20150902 ]
new_sequence
my
$p
= PDL::DateTime->new_sequence(
$start
,
$count
,
$unit
,
$step
);
# $start .. ISO 8601 date time string (starting datetime) or 'now'
# $count .. length of the sequence (incl. starting point)
# $unit .. step unit 'year', 'quarter', 'month', 'week',
# 'day', 'hour', 'minute', 'second'
# $step .. how many units there are between two seq elements (default: 1)
double_epoch
my
$dbl
=
$p
->double_epoch;
# BEWARE: precision loss, before exporting the time is truncated to miliseconds!
# returns Double piddle
longlong_epoch
my
$epoch
=
$p
->longlong_epoch;
# BEWARE: precision loss, before exporting the time is truncated to seconds!
# returns LongLong piddle
# NOTE: $p->longlong_epoch is equivalent to: longlong(floor($p->double_epoch))
# 1969-12-31T23:59:58 double_epoch = -2.0 longlong_epoch = -2
# 1969-12-31T23:59:58.001 double_epoch = -1.999 longlong_epoch = -2
# 1969-12-31T23:59:58.999 double_epoch = -1.001 longlong_epoch = -2
# 1969-12-31T23:59:59 double_epoch = -1.0 longlong_epoch = -1
# 1969-12-31T23:59:59.001 double_epoch = -0.999 longlong_epoch = -1
# 1969-12-31T23:59:59.999 double_epoch = -0.001 longlong_epoch = -1
# 1970-01-01T00:00:00 double_epoch = 0.0 longlong_epoch = 0
# 1970-01-01T00:00:00.001 double_epoch = 0.001 longlong_epoch = 0
# 1970-01-01T00:00:00.999 double_epoch = 0.999 longlong_epoch = 0
# 1970-01-01T00:00:01 double_epoch = 1.0 longlong_epoch = 1
double_ratadie
my
$dbl
=
$p
->double_ratadie;
# BEWARE: precision loss, before exporting the time is truncated to miliseconds!
# returns Double piddle
double_serialdate
my
$dbl
=
$p
->double_serialdate;
# BEWARE: precision loss, before exporting the time is truncated to miliseconds!
# returns Double piddle
double_juliandate
my
$dbl
=
$p
->double_juliandate;
# BEWARE: precision loss, before exporting the time is truncated to miliseconds!
# returns Double piddle
dt_year
my
$y
=
$p
->dt_year;
# returns: $y Short piddle (values 1 .. 9999)
dt_quarter
my
$m
=
$p
->dt_quarter;
# returns: $m Byte piddle (values 1 .. 4)
dt_month
my
$m
=
$p
->dt_month;
# returns: $m Byte piddle (values 1 .. 12)
dt_day
my
$d
=
$p
->dt_day;
# returns: $d Byte piddle (values 1 .. 31)
dt_ymd
If you need all year
, month
and day
values it is more effective to use one dt_ymd
call instead of separately calling dt_year
, dt_month
and dt_day
.
my
(
$y
,
$m
,
$d
) =
$p
->dt_ymd;
# returns 3 piddles: $y Short, $m Byte, $d Byte
dt_hour
my
$H
=
$p
->dt_hour;
# returns Byte piddle (values 0 .. 23)
dt_minute
my
$M
=
$p
->dt_minute;
# returns Byte piddle (values 0 .. 59)
dt_second
my
$S
=
$p
->dt_second;
# returns Byte piddle (values 0 .. 59)
dt_microsecond
my
$U
=
$p
->dt_microsecond;
# returns Long piddle (values 0 .. 999_999)
dt_day_of_week
my
$wd
=
$p
->dt_day_of_week;
# returns Byte piddle (values 1=Mon .. 7=Sun)
dt_day_of_year
my
$wd
=
$p
->dt_day_of_year;
# returns Short piddle (values 1 .. 366)
dt_add
my
$p
->dt_add(
$unit
,
$num
);
# adds $num datetime units
# $num can be positive (addition) or negative (subtraction)
# $unit .. 'year', 'quarter', 'month', 'week', 'day', 'hour',
# 'minute', 'second', 'millisecond', 'microsecond'
my
$p
->dt_add(
day
=> 2);
# turns e.g. 2015-08-20T23:24:25.123456Z
# into 2015-08-22T23:24:25.123456Z
my
$p
->dt_add(
day
=> -2);
# turns e.g. 2015-08-20T23:24:25.123456Z
# into 2015-08-18T23:24:25.123456Z
my
$p
->dt_add(
day
=> 2,
year
=> 3,
month
=> 1);
# turns e.g. 2015-08-20T23:24:25.123456Z
# into 2018-09-22T23:24:25.123456Z
#NOTE: supports also inplace
$p
->inplace->dt_add(
day
=> 2);
dt_align
my
$p
->dt_align(
$unit
);
# $unit .. 'year', 'quarter', 'month', 'week', 'day', 'hour',
# 'minute', 'second', 'millisecond', 'microsecond'
my
$p
->dt_align(
'minute'
);
# turns e.g. 2015-08-20T23:24:25.123456Z
# into 2015-08-20T23:24:00.000000Z
my
$p
->dt_align(
$unit
,
$upper
);
#second optional param
# $upper .. 1 or 0 (default), align to upper boundary (end of period)
# only for 'year', 'quarter', 'month', 'week'
# let's have: 2015-08-20T23:24:25.123456Z
$p
->dt_align(
'year'
);
# -> 2015-01-01
$p
->dt_align(
'year'
, 1);
# -> 2015-12-31 (the last day of year)
$p
->dt_align(
'quarter'
);
# -> 2015-07-01
$p
->dt_align(
'quarter'
, 1);
# -> 2015-09-30 (the last day of quarter)
$p
->dt_align(
'month'
);
# -> 2015-08-01
$p
->dt_align(
'month'
, 1);
# -> 2015-08-31 (the last day of month)
$p
->dt_align(
'week'
);
# -> 2015-08-17 (Monday)
$p
->dt_align(
'week'
, 1);
# -> 2015-08-23 (Sunday)
#NOTE: supports also inplace
$p
->inplace->dt_align(
'minute'
);
dt_unpdl
my
$array
=
$p
->dt_unpdl;
my
$array
=
$p
->dt_unpdl(
$format
);
my
$array
=
$p
->dt_unpdl(
'%y-%m-%d %H:%M:%S'
);
# returns perl arrayref with ISO 8601 date time strings
my
$array
=
$p
->dt_unpdl(
'auto'
);
# uses ISO 8601 format autodetected to be as short as possible
# e.g. 2015-09-07T22:53 when all piddle values have 0 seconds and 0 microseconds
# $format 'auto' is default when dt_unpdl is called without param
my
$array
=
$p
->dt_unpdl(
'epoch'
);
# returns perl arrayref (not a piddle) with epoch seconds as double
# BEWARE: precision loss, before exporting the time is truncated to miliseconds!
my
$array
=
$p
->dt_unpdl(
'epoch_int'
);
# returns perl arrayref (not a piddle) with epoch seconds as integer values
# BEWARE: precision loss, before exporting the time is truncated to seconds!
my
$array
=
$p
->dt_unpdl(
'Time::Moment'
);
# returns perl arrayref with Time::Moment objects
See Time::Moment (which we use for stringification) for supported formats.
dt_at
my
$datetime
=
$p
->dt_at(
@coords
)
#or
my
$datetime
=
$p
->dt_at(
@coords
,
$format
)
# returns ISO 8601 date time string for value at given piddle co-ordinates
# optional $format arg - same as by dt_unpdl
dt_set
$p
->dt_set(
@coords
,
$datetime_or_epoch
);
# sets $datetime_or_epoch as value at given piddle co-ordinates
# $datetime_or_epoch can be ISO 8601 string or epoch seconds (double or int)
dt_diff
my
$deltas
=
$p
->dt_diff;
#or
my
$deltas
=
$p
->dt_diff(
$unit
);
# $unit .. 'week', 'day', 'hour', 'minute', 'second', 'millisecond'
dt_periodicity
my
$per
=
$p
->dt_periodicity;
# estimates the periodicity by calculating the median time between observations
# returns: "microsecond", "millisecond", "second", "minute"
# "hour", "day", "week", "month", "quarter"
# or an empty string
dt_startpoints
Extract index values corresponding to the first observations given a period specified by $unit
my
$end_idx
=
$p
->dt_startpoints(
$unit
);
# $unit .. accepts same values as dt_align
Example:
my
$dt
= PDL::DateTime->new_from_datetime([
qw/
2015-03-24 2015-03-25 2015-03-28 2015-04-01
2015-04-02 2015-04-30 2015-05-01 2015-05-10
/
]);
$dt
->dt_startpoints(
'month'
);
# prints: [0 3 6]
$dt
->dt_startpoints(
'quarter'
);
# prints: [0 3]
dt_endpoints
Extract index values corresponding to the last observations given a period specified by $unit
my
$end_idx
=
$p
->dt_endpoints(
$unit
);
# $unit .. accepts same values as dt_align
Example:
my
$dt
= PDL::DateTime->new_from_datetime([
qw/
2015-03-24 2015-03-25 2015-03-28 2015-04-01
2015-04-02 2015-04-30 2015-05-01 2015-05-10
/
]);
$dt
->dt_endpoints(
'month'
);
# prints: [2 5 7]
$dt
->dt_endpoints(
'quarter'
);
# prints: [2 7]
dt_slices
Combines "dt_startpoints" and "dt_endpoints" and returns 2D piddle like this:
my
$dt
= PDL::DateTime->new_from_datetime([
qw/
2015-03-24 2015-03-25 2015-03-28 2015-04-01
2015-04-02 2015-04-30 2015-05-01 2015-05-10
/
]);
$dt
->dt_slices(
'month'
);
# [
# [0 2] ... start index == 0, end index == 2
# [3 5] ... start index == 3, end index == 5
# [6 7] ... start index == 6, end index == 7
# ]
$dt
->dt_slices(
'quarter'
);
# [
# [0 2]
# [3 7]
# ]
The piddle returned by this function can be passed to apply_slice.
dt_nperiods
Calculate the number of periods specified by $unit
in a given time series. The resulting value is approximate, derived from counting the endpoints.
$dt
->dt_nperiods(
$unit
)
# $unit .. 'year', 'quarter', 'month', 'week', 'day', 'hour',
# 'minute', 'second', 'millisecond', 'microsecond'
is_increasing
$dt
->is_increasing ?
"is increasing"
:
"no"
;
#or
$dt
->is_increasing(1) ?
"is strictly increasing"
:
"no"
;
is_decreasing
$dt
->is_decreasing ?
"is decreasing"
:
"no"
;
#or
$dt
->is_decreasing(1) ?
"is strictly decreasing"
:
"no"
;
is_uniq
$dt
->is_uniq ?
"all items are uniq"
:
"no"
;
is_regular
$dt
->is_regular ?
"all periods between items are the same"
:
"no"
;
SEE ALSO
LICENSE
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
COPYRIGHT
2015+ KMX <kmx@cpan.org>