chronos 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +27 -0
- data/HISTORY.rdoc +4 -0
- data/LICENSE.txt +52 -0
- data/MANIFEST.txt +51 -0
- data/NOTES.rdoc +85 -0
- data/README.rdoc +125 -0
- data/Rakefile +34 -0
- data/TODO.rdoc +63 -0
- data/bench/completebench.rb +24 -0
- data/ext/cchronos/extconf.rb +5 -0
- data/ext/chronos_core/extconf.rb +5 -0
- data/lib/chronos.rb +208 -0
- data/lib/chronos/calendar.rb +16 -0
- data/lib/chronos/calendar/gregorian.rb +94 -0
- data/lib/chronos/data/zones.tab +424 -0
- data/lib/chronos/datetime.rb +299 -0
- data/lib/chronos/datetime/gregorian.rb +698 -0
- data/lib/chronos/duration.rb +141 -0
- data/lib/chronos/duration/gregorian.rb +261 -0
- data/lib/chronos/durationtotext.rb +42 -0
- data/lib/chronos/exceptions.rb +16 -0
- data/lib/chronos/gregorian.rb +27 -0
- data/lib/chronos/interval.rb +132 -0
- data/lib/chronos/interval/gregorian.rb +80 -0
- data/lib/chronos/locale/parsers/de_CH.rb +50 -0
- data/lib/chronos/locale/parsers/en_US.rb +1 -0
- data/lib/chronos/locale/parsers/generic.rb +21 -0
- data/lib/chronos/locale/strings/de_DE.yaml +76 -0
- data/lib/chronos/locale/strings/en_US.yaml +76 -0
- data/lib/chronos/minimalistic.rb +37 -0
- data/lib/chronos/numeric/gregorian.rb +100 -0
- data/lib/chronos/ruby.rb +6 -0
- data/lib/chronos/version.rb +21 -0
- data/lib/chronos/zone.rb +212 -0
- data/rake/initialize.rb +116 -0
- data/rake/lib/assesscode.rb +59 -0
- data/rake/lib/bonesplitter.rb +245 -0
- data/rake/lib/projectclass.rb +69 -0
- data/rake/tasks/copyright.rake +24 -0
- data/rake/tasks/gem.rake +119 -0
- data/rake/tasks/git.rake +40 -0
- data/rake/tasks/loc.rake +33 -0
- data/rake/tasks/manifest.rake +63 -0
- data/rake/tasks/meta.rake +16 -0
- data/rake/tasks/notes.rake +36 -0
- data/rake/tasks/post_load.rake +18 -0
- data/rake/tasks/rdoc.rake +73 -0
- data/rake/tasks/rubyforge.rake +67 -0
- data/rake/tasks/spec.rake +55 -0
- data/spec/bacon_helper.rb +43 -0
- data/spec/lib/chronos/datetime/gregorian_spec.rb +314 -0
- data/spec/lib/chronos/datetime_spec.rb +219 -0
- data/spec/lib/chronos_spec.rb +91 -0
- metadata +111 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007-2008 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
# This file is just a shortcut to require all relevent files
|
10
|
+
# for gregorian and setting Chronos to use the gregorian classes
|
11
|
+
# per default.
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
require 'chronos'
|
16
|
+
require 'chronos/calendar/gregorian'
|
17
|
+
require 'chronos/datetime/gregorian'
|
18
|
+
require 'chronos/duration/gregorian'
|
19
|
+
require 'chronos/interval/gregorian'
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
Chronos.use :Gregorian
|
24
|
+
Datetime = Chronos::Datetime::Gregorian
|
25
|
+
Duration = Chronos::Duration::Gregorian
|
26
|
+
Interval = Chronos::Interval::Gregorian
|
27
|
+
Calendar = Chronos::Calendar::Gregorian
|
@@ -0,0 +1,132 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007-2008 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Chronos
|
10
|
+
|
11
|
+
# An Interval is determinated by a start and an end Datetime.
|
12
|
+
# Unlike in Duration, this allows to determine the months part exactly in
|
13
|
+
# seconds (and therefore minutes, hours, days, weeks).
|
14
|
+
# That opens up the possibility to say how
|
15
|
+
class Interval
|
16
|
+
ValidFixed = [:begin, :end].freeze
|
17
|
+
InspectFixedBegin = "<%p [%p] - %p, %p>".freeze
|
18
|
+
InspectFixedEnd = "<%p %p - [%p], %p>".freeze
|
19
|
+
|
20
|
+
# The smaller of the two datetimes
|
21
|
+
attr_reader :begin
|
22
|
+
|
23
|
+
# The bigger of the two datetimes
|
24
|
+
attr_reader :end
|
25
|
+
|
26
|
+
# Which end is fixed, plays a role when adding, subtracting, multiplying, dividing, ...
|
27
|
+
attr_reader :fixed
|
28
|
+
|
29
|
+
# unlike new, between always creates a positive interval
|
30
|
+
# it will switch limit_a and limit_b if limit_a > limit_b
|
31
|
+
# it always fixates :begin
|
32
|
+
def self.between(limit_a, limit_b)
|
33
|
+
limit_a > limit_b ? new(limit_b, limit_a, false, :begin) : new(limit_a, limit_b, false, :begin)
|
34
|
+
end
|
35
|
+
|
36
|
+
# create a new interval that lasts from start_date until end_date
|
37
|
+
# === Arguments
|
38
|
+
# limit_a:: one of the two limiting datetimes
|
39
|
+
# limit_b:: the other of the two limiting datetimes
|
40
|
+
# fixated:: which end to fixate for operations. Defaults to :begin, valid values are (Symbols):
|
41
|
+
# begin:: The smaller datetime is fixated
|
42
|
+
# end:: The smaller datetime is fixated
|
43
|
+
def initialize(limit_a, limit_b, fixed=nil)
|
44
|
+
@fixed = fixed || :begin
|
45
|
+
raise ArgumentError, "limites don't have the same signature" unless (limit_a.time? == limit_b.time? && limit_a.date? == limit_b.date?)
|
46
|
+
raise ArgumentError, "invalid fixed, must be :begin or :end" unless ValidFixed.include?(@fixed)
|
47
|
+
|
48
|
+
@language = limit_a.language
|
49
|
+
|
50
|
+
if limit_a > limit_b then
|
51
|
+
@begin = limit_b
|
52
|
+
@end = limit_a
|
53
|
+
@negative = false
|
54
|
+
else
|
55
|
+
@begin = limit_a
|
56
|
+
@end = limit_b
|
57
|
+
@negative = true
|
58
|
+
end
|
59
|
+
|
60
|
+
overflow = 0
|
61
|
+
picoseconds = @end.ps_number - @begin.ps_number if @begin.time?
|
62
|
+
days = @end.day_number - @begin.day_number if @begin.date?
|
63
|
+
overflow, picoseconds = *picoseconds.divmod(PS_IN_DAY) if @begin.time?
|
64
|
+
@duration = Duration.new(days+overflow, picoseconds, @language)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Returns the same Interval but with begin as fixpoint for operations
|
68
|
+
def fixed_begin
|
69
|
+
self.class.new(@begin, @end, :begin)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Returns the same interval but with end as fixpoint for operations
|
73
|
+
def fixed_end
|
74
|
+
self.class.new(@begin, @end, :end)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Enlarges the Interval by duration away from the fixed end
|
78
|
+
def +(duration)
|
79
|
+
if @fixed == :begin then
|
80
|
+
self.class.new(@begin, @end+duration, @fixed)
|
81
|
+
else
|
82
|
+
self.class.new(@begin-duration, @end, @fixed)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Shortens the Interval by duration towards from the fixed end
|
87
|
+
# will raise if self < duration
|
88
|
+
def -(duration)
|
89
|
+
if @fixed == :begin then
|
90
|
+
self.class.new(@begin, @end-duration, @fixed)
|
91
|
+
else
|
92
|
+
self.class.new(@begin+duration, @end, @fixed)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# The number of picoseconds
|
97
|
+
def picoseconds
|
98
|
+
@duration.picoseconds
|
99
|
+
end
|
100
|
+
|
101
|
+
def days
|
102
|
+
@duration.days
|
103
|
+
end
|
104
|
+
|
105
|
+
def values_at(*keys)
|
106
|
+
to_hash.values_at(*keys)
|
107
|
+
end
|
108
|
+
|
109
|
+
# converts this interval to a duration
|
110
|
+
# if you set as_seconds to true it will convert the
|
111
|
+
# month primitive to seconds and use that
|
112
|
+
def to_duration
|
113
|
+
@duration
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_hash
|
117
|
+
@duration.to_hash.merge(:begin => @begin, :end => @end, :language => @language)
|
118
|
+
end
|
119
|
+
|
120
|
+
def format(string)
|
121
|
+
raise NoMethodError
|
122
|
+
end
|
123
|
+
|
124
|
+
def inspect
|
125
|
+
if @fixed == :begin then
|
126
|
+
sprintf InspectFixedBegin, self.class, @begin, @end, @duration
|
127
|
+
else
|
128
|
+
sprintf InspectFixedEnd, self.class, @begin, @end, @duration
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright 2007-2008 by Stefan Rusterholz.
|
3
|
+
# All rights reserved.
|
4
|
+
# See LICENSE.txt for permissions.
|
5
|
+
#++
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
module Chronos
|
10
|
+
class Interval
|
11
|
+
|
12
|
+
# A Gregorian Interval extens Interval by months.
|
13
|
+
# Unlike in Gregorian Durations, months exactly defined in seconds (and therefore minutes,
|
14
|
+
# hours, days, weeks).
|
15
|
+
# Internally a gregorian interval is stored as total picoseconds after days + days between the
|
16
|
+
# two dates and additionally the months + days after months + picoseconds after days. For
|
17
|
+
class Gregorian < Interval
|
18
|
+
ValidFixed = [:begin, :end].freeze
|
19
|
+
|
20
|
+
# The smaller of the two datetimes
|
21
|
+
attr_reader :begin
|
22
|
+
|
23
|
+
# The bigger of the two datetimes
|
24
|
+
attr_reader :end
|
25
|
+
|
26
|
+
# Which end is fixed, plays a role when adding, subtracting, multiplying, dividing, ...
|
27
|
+
attr_reader :fixed
|
28
|
+
|
29
|
+
# unlike new, between always creates a positive interval
|
30
|
+
# it will switch limit_a and limit_b if limit_a > limit_b
|
31
|
+
# it always fixates :begin
|
32
|
+
def self.between(limit_a, limit_b)
|
33
|
+
limit_a > limit_b ? new(limit_b, limit_a, false, :begin) : new(limit_a, limit_b, false, :begin)
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(limit_a, limit_b, fixed=nil)
|
37
|
+
super(limit_a, limit_b, fixed)
|
38
|
+
picoseconds = @end.ps_number - @begin.ps_number if @begin.time?
|
39
|
+
days, picoseconds = *picoseconds.divmod(PS_IN_DAY) if @begin.time?
|
40
|
+
months = 0
|
41
|
+
|
42
|
+
if @begin.date? then
|
43
|
+
a = Datetime.new(@begin.day_number, @begin.ps_number, ::Chronos::UTC)
|
44
|
+
b = Datetime.new(@end.day_number, @end.ps_number, ::Chronos::UTC)
|
45
|
+
days_after_months = days+b.day_of_month-a.day_of_month
|
46
|
+
months = b.year*12+b.month-a.year*12-a.month
|
47
|
+
|
48
|
+
# move 1 month forward
|
49
|
+
if days_after_months < 0 then
|
50
|
+
days_after_months += a.days_in_month
|
51
|
+
months -= 1
|
52
|
+
end
|
53
|
+
|
54
|
+
days += b.day_number - a.day_number
|
55
|
+
bsd = a.day_of_month > b.day_of_month ||
|
56
|
+
(start_date.time? && a.day_of_month == b.day_of_month && seconds < 0)
|
57
|
+
month1 = a.year*12+a.month+(bsd ? 1 : 0)
|
58
|
+
month2 = b.year*12+b.month
|
59
|
+
months = month2 - month1
|
60
|
+
a2y,a2m = *(month1-1).divmod(12)
|
61
|
+
a, b = Datetime.civil(a2y, a2m+1, 1), Datetime.civil(b.year, b.month, 1)
|
62
|
+
|
63
|
+
seconds_in_months = (b.day_number-a.day_number)*86400
|
64
|
+
p [seconds, seconds_in_months]
|
65
|
+
seconds -= seconds_in_months
|
66
|
+
|
67
|
+
b2y,b2m = *(month1+(months.div(12)*12)).divmod(12)
|
68
|
+
b = Datetime.civil(b2y, b2m+1, 1)
|
69
|
+
seconds_in_years = (b.day_number-a.day_number)*86400
|
70
|
+
end
|
71
|
+
|
72
|
+
@gregorian_duration = Duration::Gregorian.new(months, days+overflow, picoseconds, @language)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_gregorian_duration
|
76
|
+
@gregorian_duration
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# 21. 12. 1982
|
2
|
+
# 21.12.1982
|
3
|
+
# 21. Dezember 1982
|
4
|
+
# 23:15 Uhr
|
5
|
+
# 23.15 Uhr
|
6
|
+
|
7
|
+
add(/#{day}\. ?#{month}\. ?#{year}/, :day, :month, :year)
|
8
|
+
add(/#{day}\. #{monthname} #{year}/, :day, :month, :year)
|
9
|
+
add(/#{hour}(?:[:.]#{minute}(?:[:.]#{second})?)?/, :hour, :minute, :second)
|
10
|
+
add(/gestern/) {
|
11
|
+
d = Chronos::Datetime::Gregorian.today
|
12
|
+
s = Chronos::Duration::Gregorian.new :days => 1
|
13
|
+
d.to_hash(:year, :month, :day)
|
14
|
+
}
|
15
|
+
add(/heute/) {
|
16
|
+
d = Chronos::Datetime::Gregorian.yesterday; d.to_hash(:year, :month, :day)
|
17
|
+
}
|
18
|
+
'#(gestern)#':
|
19
|
+
- yesterday
|
20
|
+
'#(heute)#':
|
21
|
+
- today
|
22
|
+
'#(morgen)#':
|
23
|
+
- tomorrow
|
24
|
+
'#(jetzt)#':
|
25
|
+
- now
|
26
|
+
'#(\d{1,2})\.(\d{1,2})\.(\d{4}|\d{2})?#':
|
27
|
+
- d
|
28
|
+
- m
|
29
|
+
- y
|
30
|
+
'#(\d{1,2})\. (\d{1,2})\. (\d{4}|\d{2}(?![.:]))?#':
|
31
|
+
- d
|
32
|
+
- m
|
33
|
+
- y
|
34
|
+
'#(\d{1,2})\. (\w{3,})\.? ?(\d{4}|\d{2})?#':
|
35
|
+
- d
|
36
|
+
- T
|
37
|
+
- y
|
38
|
+
'#(\d{1,2})\:(\d{1,2})h?#':
|
39
|
+
- H
|
40
|
+
- M
|
41
|
+
'#(\d{1,2})\:(\d{1,2})(h| uhr)?#':
|
42
|
+
- H
|
43
|
+
- M
|
44
|
+
'#(?:\A|[^\.\d])(\d{1,2})\.(\d{1,2})(?![\.\d])(h| uhr)?#':
|
45
|
+
- H
|
46
|
+
- M
|
47
|
+
- 0
|
48
|
+
'#(\d{1,2})(h| uhr)#':
|
49
|
+
- H
|
50
|
+
- 0
|
@@ -0,0 +1 @@
|
|
1
|
+
add_format "%m/%d/%Y"
|
@@ -0,0 +1,21 @@
|
|
1
|
+
add_format_as "Y", /(\d{4})/, :year # 4 digits
|
2
|
+
add_format_as "m", /(0?[1-9]|1[012])/, :month # 1-12 with optional leading zero
|
3
|
+
add_format_as "d", /(0?[1-9]|[12]\d|3[01])/, :day_of_month # 1-31 with optional leading zero
|
4
|
+
add_format_as "H", /([01]?\d|2[123])/, :hour # 0-23 with optional leading zero
|
5
|
+
add_format_as "M", /([0-5]?\d)/, :minute # 0-59 with optional leading zero
|
6
|
+
add_format_as "S", /([0-5]?\d|60)/, :second # 0-60 with optional leading zero (leap second)
|
7
|
+
add_format_as "Z", /(#{Chronos::TimezonesByName.keys.sort.join('|')})/, :timezone do |parser, matches| # timezones are known to have no special chars, no escaping required
|
8
|
+
if tz = Chronos::TimezonesByName[matches.first] then
|
9
|
+
tz.offset
|
10
|
+
end
|
11
|
+
end
|
12
|
+
add_format_as "z", /(+-)/, :timezone do |parser, matches| # timezones are known to have no special chars, no escaping required
|
13
|
+
if tz = Chronos::TimezonesByName[matches.first] then
|
14
|
+
tz.offset
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
add_format_as "iso_date", /#{Y}-(#{m})-#{d}/, :year, :month, :day
|
19
|
+
add_format_as
|
20
|
+
|
21
|
+
add_format(/#{iso_date}/)
|
@@ -0,0 +1,76 @@
|
|
1
|
+
---
|
2
|
+
:monthname:
|
3
|
+
- Januar
|
4
|
+
- Februar
|
5
|
+
- März
|
6
|
+
- April
|
7
|
+
- Mai
|
8
|
+
- Juni
|
9
|
+
- Juli
|
10
|
+
- August
|
11
|
+
- September
|
12
|
+
- Oktober
|
13
|
+
- November
|
14
|
+
- Dezember
|
15
|
+
:monthnameshort:
|
16
|
+
- Jan
|
17
|
+
- Feb
|
18
|
+
- Mär
|
19
|
+
- Apr
|
20
|
+
- Mai
|
21
|
+
- Jun
|
22
|
+
- Jul
|
23
|
+
- Aug
|
24
|
+
- Sep
|
25
|
+
- Okt
|
26
|
+
- Nov
|
27
|
+
- Dez
|
28
|
+
:dayname:
|
29
|
+
- Montag
|
30
|
+
- Dienstag
|
31
|
+
- Mittwoch
|
32
|
+
- Donnerstag
|
33
|
+
- Freitag
|
34
|
+
- Samstag
|
35
|
+
- Sonntag
|
36
|
+
:daynameshort:
|
37
|
+
- Mo
|
38
|
+
- Di
|
39
|
+
- Mi
|
40
|
+
- Do
|
41
|
+
- Fr
|
42
|
+
- Sa
|
43
|
+
- So
|
44
|
+
:picosecond:
|
45
|
+
~: Picosekunden
|
46
|
+
1: Picosekunde
|
47
|
+
:nanosecond:
|
48
|
+
~: Nanosekunden
|
49
|
+
1: Nanosekunde
|
50
|
+
:microsecond:
|
51
|
+
~: Mikrosekunden
|
52
|
+
1: Mikrosekunde
|
53
|
+
:millisecond:
|
54
|
+
~: Millisekunden
|
55
|
+
1: Millisekunde
|
56
|
+
:second:
|
57
|
+
~: Sekunden
|
58
|
+
1: Sekunde
|
59
|
+
:minute:
|
60
|
+
~: Minuten
|
61
|
+
1: Minute
|
62
|
+
:hour:
|
63
|
+
~: Stunden
|
64
|
+
1: Stunde
|
65
|
+
:day:
|
66
|
+
~: Tage
|
67
|
+
1: Tag
|
68
|
+
:week:
|
69
|
+
~: Wochen
|
70
|
+
1: Woche
|
71
|
+
:month:
|
72
|
+
~: Monate
|
73
|
+
1: Monat
|
74
|
+
:year:
|
75
|
+
~: Jahre
|
76
|
+
1: Jahr
|
@@ -0,0 +1,76 @@
|
|
1
|
+
---
|
2
|
+
:monthname:
|
3
|
+
- january
|
4
|
+
- february
|
5
|
+
- march
|
6
|
+
- april
|
7
|
+
- may
|
8
|
+
- june
|
9
|
+
- july
|
10
|
+
- august
|
11
|
+
- september
|
12
|
+
- october
|
13
|
+
- november
|
14
|
+
- december
|
15
|
+
:monthnameshort:
|
16
|
+
- jan
|
17
|
+
- feb
|
18
|
+
- mar
|
19
|
+
- apr
|
20
|
+
- may
|
21
|
+
- jun
|
22
|
+
- jul
|
23
|
+
- aug
|
24
|
+
- sep
|
25
|
+
- oct
|
26
|
+
- nov
|
27
|
+
- dec
|
28
|
+
:dayname:
|
29
|
+
- monday
|
30
|
+
- tuesday
|
31
|
+
- wednesday
|
32
|
+
- thursday
|
33
|
+
- friday
|
34
|
+
- saturday
|
35
|
+
- sunday
|
36
|
+
:daynameshort:
|
37
|
+
- mo
|
38
|
+
- tu
|
39
|
+
- we
|
40
|
+
- th
|
41
|
+
- fr
|
42
|
+
- sa
|
43
|
+
- su
|
44
|
+
:picosecond:
|
45
|
+
~: picoseconds
|
46
|
+
1: picosecond
|
47
|
+
:nanosecond:
|
48
|
+
~: nanoseconds
|
49
|
+
1: nanosecond
|
50
|
+
:microsecond:
|
51
|
+
~: microseconds
|
52
|
+
1: microsecond
|
53
|
+
:millisecond:
|
54
|
+
~: milliseconds
|
55
|
+
1: millisecond
|
56
|
+
:second:
|
57
|
+
~: seconds
|
58
|
+
1: second
|
59
|
+
:minute:
|
60
|
+
~: minutes
|
61
|
+
1: minute
|
62
|
+
:hour:
|
63
|
+
~: hours
|
64
|
+
1: hour
|
65
|
+
:day:
|
66
|
+
~: days
|
67
|
+
1: day
|
68
|
+
:week:
|
69
|
+
~: weeks
|
70
|
+
1: week
|
71
|
+
:month:
|
72
|
+
~: months
|
73
|
+
1: month
|
74
|
+
:year:
|
75
|
+
~: years
|
76
|
+
1: year
|