zones 0.6.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +44 -7
  3. data/lib/zones.rb +74 -104
  4. data/zones.gemspec +3 -5
  5. metadata +4 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f86231105060ba0d2a2e5de9b5d5e1a12697442eab2f53e25141ae9e364c595
4
- data.tar.gz: 435fd13071ba665a0e3c8f4cca2162a804ca160ffee145ca179558a4e22f383d
3
+ metadata.gz: 97eeda72622d0c6a5bbd3a63d44c97bae7acebc73d51f686d66b8f34750d71fd
4
+ data.tar.gz: 73b2b1a0042828cf4c82bd57efe049b7b8221df1a7676635d66275f4f987f3aa
5
5
  SHA512:
6
- metadata.gz: 10f84f521cefa6e9ef0d3933338d8c6666dde86908fb18cf8d530ffe71535e95cb8c028a1537356edba17ce5d36a6fdf71a86dfc040208a178b0ea8282adfa48
7
- data.tar.gz: 5929966234fda57b8b1fac23ace116f43369e3a68a994ad4413d56ed001c415efc22e850e27f2a2de9175bfb8bd6a363575d14d408a7618a69b246c18b6e3fc6
6
+ metadata.gz: ce3ab3febcccb6ca83b314edc650a7361079e264e487342c370149a4e8df90bee6ca915671ed4fcca4238b3ecfc9fa2d99aa8c4033cd5f08c6a6d4c34956a889
7
+ data.tar.gz: ff075b5885fd403fd4cef89b224ff692c6c346b5919fcc8735097393ac21bd0cefb437830db8719ac0d5f9ccc9142630762fb6cb7bbee0483f19dd23d46d6a98
data/README.md CHANGED
@@ -1,17 +1,54 @@
1
1
  # zones
2
2
 
3
- `zones` is a Ruby gem that makes it easy to parse time and convert it between time zones.
3
+ A friendly Ruby gem for time parsing and time zone conversion.
4
+
5
+ ## API
6
+
7
+ ```ruby
8
+ Time.tz(str, toz=nil, asz=nil) # create a new Time object with a time zone
9
+ Time.tz!(str, asz="UTC", toz=nil) # overrides original time zone and swaps params
10
+ Time#to(zone) # converts a time to a new time zone
11
+ Time#as(zone) # keeps the time, but changes the time zone
12
+
13
+ String#to_tz # calls Time.tz
14
+ String#to_tz! # calls Time.tz!
15
+ String#to_day # calls Date.to_day
16
+ String#iso_date # parses and shows ISO date (YYYY-MM-DD)
17
+ ```
4
18
 
5
19
  ## Examples
6
20
 
21
+ Parsing strings:
22
+
7
23
  ```ruby
8
- # when parsing, the "!" means to ignore the supplied time zone / offset
9
- x = "3 August 2017 11:43 +0415".to_tz("US/Pacific") # 2017-08-03 00:28:00 -0700
10
- y = "3 August 2017 11:43 +0415".to_tz!("US/Pacific") # 2017-08-03 11:43:00 -0700
24
+ # no argument means to parse the value as is; "!" ignores the time zone and uses UTC
25
+ x = "3 August 2013 11:43 +0415".to_tz # 2013-08-03 11:43:00 +0415
26
+ y = "3 August 2013 11:43 +0415".to_tz! # 2013-08-03 11:43:00 +0000
11
27
 
12
- # when converting, the "!" means to only change the offset
13
- x.to_tz("US/Eastern") # 2017-08-03 03:28:00 -0400
14
- y.to_tz!("US/Eastern") # 2017-08-03 11:43:00 -0400
28
+ # one argument means to convert to that time zone, use "!" to ignore the original offset
29
+ x = "3 August 2013 11:43 +0415".to_tz("US/Pacific") # 2013-08-03 00:28:00 -0700
30
+ y = "3 August 2013 11:43 +0415".to_tz!("US/Pacific") # 2013-08-03 11:43:00 -0700
31
+
32
+ # use two arguments to indicate source and destination time zones, "!" swaps the order
33
+ x = "3 August 2013 11:43 +0415".to_tz("US/Pacific", "America/Caracas") # 2013-08-03 09:13:00 -0700
34
+ y = "3 August 2013 11:43 +0415".to_tz!("US/Pacific", "America/Caracas") # 2013-08-03 14:13:00 -0430
35
+ ```
36
+
37
+ Converting values:
38
+
39
+ ```ruby
40
+ # 'as' keeps the time but changes the time zone, 'to' converts to a new time zone
41
+ x = "May 29, 2023 6:15pm -06:00".to_tz # 2023-05-29 18:15:00 -0600
42
+ x.as("US/Eastern") # 2023-05-29 18:15:00 -0400
43
+ x.to("US/Eastern") # 2023-05-29 20:15:00 -0400
44
+ ```
45
+
46
+ Sample formats:
47
+
48
+ ```ruby
49
+ x = "4/13/1971 19:25 -0700".to_tz # 1971-04-13 19:25:00 -0700
50
+ x = "13 May 2022 11:20PM".to_tz # 2022-05-13 23:20:00 -0600
51
+ x = "September 24, 2008".iso_date # 2008-09-24
15
52
  ```
16
53
 
17
54
  ## License
data/lib/zones.rb CHANGED
@@ -1,49 +1,42 @@
1
1
  require "tzinfo"
2
2
 
3
- # ==[ Dart uses the folllowing ]==
4
- #
5
- # date ::= yeardate time_opt timezone_opt
6
- # yeardate ::= year colon_opt month colon_opt day
7
- # year ::= sign_opt digit{4,6}
8
- # colon_opt :: <empty> | ':'
9
- # sign ::= '+' | '-'
10
- # sign_opt ::= <empty> | sign
11
- # month ::= digit{2}
12
- # day ::= digit{2}
13
- # time_opt ::= <empty> | (' ' | 'T') hour minutes_opt
14
- # minutes_opt ::= <empty> | colon_opt digit{2} seconds_opt
15
- # seconds_opt ::= <empty> | colon_opt digit{2} millis_opt
16
- # micros_opt ::= <empty> | ('.' | ',') digit+
17
- # timezone_opt ::= <empty> | space_opt timezone
18
- # space_opt :: ' ' | <empty>
19
- # timezone ::= 'z' | 'Z' | sign digit{2} timezonemins_opt
20
- # timezonemins_opt ::= <empty> | colon_opt digit{2}
21
- #
22
- # static final RegExp _parseFormat =
23
- # RegExp(r'^([+-]?\d{4,6})-?(\d\d)-?(\d\d)' // Day part.
24
- # r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:[.,](\d+))?)?)?' // Time part.
25
- # r'( ?[zZ]| ?([-+])(\d\d)(?::?(\d\d))?)?)?$'); // Timezone part.
3
+ module MonthValue
4
+ def month_value(str)
5
+ (val = str.to_i).zero? ? (@month_value ||= {
6
+ "jan" => 1, "january" => 1, "jul" => 7, "july" => 7,
7
+ "feb" => 2, "february" => 2, "aug" => 8, "august" => 8,
8
+ "mar" => 3, "march" => 3, "sep" => 9, "september" => 9,
9
+ "apr" => 4, "april" => 4, "oct" => 10, "october" => 10,
10
+ "may" => 5, "nov" => 11, "november" => 11,
11
+ "jun" => 6, "june" => 6, "dec" => 12, "december" => 12,
12
+ })[str.downcase] : val or raise "bad month: #{str}"
13
+ end
14
+ end
26
15
 
27
16
  class Date
17
+ extend MonthValue
18
+
28
19
  def self.parse_str(str)
29
20
  case str
30
- when %r!^((?:19|20)\d\d)(\d\d)(\d\d)(\d\d)!
21
+ when %r!^((?:19|20)\d\d)(\d\d)(\d\d)!
31
22
  ymd = [$1.to_i, $2.to_i, $3.to_i]
32
23
  when %r!^
33
- (?:(0[1-9]|[12]\d|3[01]|[1-9][-/ ])[-/ ]? # $1: day
34
- ((?>[a-z]{3,9}))[-/ ]? # $2: month
35
- ((?>19|20)\d\d) # $3: year
24
+ (?:(0[1-9]|[12]\d|3[01]|[1-9](?=\D))[-/\s]? # $1: day
25
+ ( (?>[a-z]{3,9}))[-/\s]? # $2: month (no digits allowed here)
26
+ ((?>19|20)\d\d) # $3: year
36
27
  | # or...
37
- ((?>19|20)\d\d)[-/]? # $4: year
38
- (0[1-9]|1[012]|[1-9][-/])[-/]? # $5: month
39
- (0[1-9]|[12]\d|3[01]|[1-9][\sT]) # $6: day
28
+ ((?>19|20)\d\d)[-/\s]? # $4: year
29
+ (0[1-9]|1[012]|[1-9](?=\D)|(?>[a-z]{3,9}))[-/\s]? # $5: month
30
+ (0[1-9]|[12]\d|3[01]|[1-9]\b) # $6: day
40
31
  | # or...
41
- (0[1-9]|1[012]|[1-9][-/])[-/]? # $7: month
42
- (0[1-9]|[12]\d|3[01]|[1-9][-/])[-/]? # $8: day
43
- ((?>19|20)\d\d) # $9: year
32
+ (0[1-9]|1[012]|[1-9](?=\D)|(?>[a-z]{3,9}))[-/\s]? # $7: month
33
+ (0[1-9]|[12]\d|3[01]|[1-9](?=\D)),?[-/\s]? # $8: day
34
+ ((?>19|20)\d\d) # $9: year
44
35
  )
45
36
  !iox
46
- ymd = $1 ? [$3.to_i, month_num($2), $1.to_i] : $4 ? [$4.to_i, $5.to_i, $6.to_i] : [$9.to_i, $7.to_i, $8.to_i]
37
+ ymd = $1 ? [ $3.to_i, month_value($2), $1.to_i] : \
38
+ $4 ? [ $4.to_i, month_value($5), $6.to_i] : \
39
+ [ $9.to_i, month_value($7), $8.to_i]
47
40
  else
48
41
  raise "can't parse: #{str}"
49
42
  end
@@ -58,113 +51,90 @@ class Date
58
51
  end
59
52
 
60
53
  class Time
61
- def self.parse_str(str, ignore_offset=false)
54
+ extend MonthValue
55
+
56
+ def self.parse_str(str)
62
57
  case str
63
- when %r!^((?:19|20)\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)?\.?(\d+)?([-+]\d\d:?\d\d)?!
58
+ when %r!^
59
+ ((?:19|20)\d\d)[-/\s]?(\d\d)[-/\s]?(\d\d)\s? # $1-3: year, month, day
60
+ (\d\d):?(\d\d):?(\d\d)?\.?(\d+)? # $4-7: hour, min, sec, decimal
61
+ ([-+]\d\d:?\d\d)? # $8 : offset
62
+ !x
64
63
  ymd = [$1.to_i, $2.to_i, $3.to_i]
65
64
  hms = [$4.to_i, $5.to_i, "#{$6}.#{$7}".to_f]
66
- off = $8.sub(/(\d)(\d\d)$/,'\1:\2') if $8 && !ignore_offset
65
+ off = $8.sub(/(\d)(\d\d)$/,'\1:\2') if $8
67
66
  when %r!^
68
- (?:(0[1-9]|[12]\d|3[01]|[1-9][-/ ])[-/ ]? # $1: day
69
- ((?>[a-z]{3,9}))[-/ ]? # $2: month
70
- ((?>19|20)\d\d) # $3: year
67
+ (?:(0[1-9]|[12]\d|3[01]|[1-9](?=\D))[-/\s]? # $1: day
68
+ ( (?>[a-z]{3,9}))[-/\s]? # $2: month (no digits allowed here)
69
+ ((?>19|20)\d\d) # $3: year
71
70
  | # or...
72
- ((?>19|20)\d\d)[-/]? # $4: year
73
- (0[1-9]|1[012]|[1-9][-/])[-/]? # $5: month
74
- (0[1-9]|[12]\d|3[01]|[1-9][\sT]) # $6: day
71
+ ((?>19|20)\d\d)[-/\s]? # $4: year
72
+ (0[1-9]|1[012]|[1-9](?=\D)|(?>[a-z]{3,9}))[-/\s]? # $5: month
73
+ (0[1-9]|[12]\d|3[01]|[1-9](?=\D)) # $6: day
75
74
  | # or...
76
- (0[1-9]|1[012]|[1-9][-/])[-/]? # $7: month
77
- (0[1-9]|[12]\d|3[01]|[1-9][-/])[-/]? # $8: day
78
- ((?>19|20)\d\d) # $9: year
75
+ (0[1-9]|1[012]|[1-9](?=\D)|(?>[a-z]{3,9}))[-/\s]? # $7: month
76
+ (0[1-9]|[12]\d|3[01]|[1-9](?=\D)),?[-/\s]? # $8: day
77
+ ((?>19|20)\d\d) # $9: year
79
78
  )\s?T?\s?
80
- (\d\d?)? # $10: hour
81
- :?(\d\d)? # $11: min
82
- :?(\d\d)? # $12: sec
83
- \.?(\d+)? # $13: dec
84
- \s?(?:(a|p)?m)? # $14: am/pm
85
- \s?(([-+])?(\d\d):?(\d\d)|UTC|GMT)? # $15: offset ($16=sign, $17=hours, $18=mins)
79
+ (\d\d?)? # $10: hour
80
+ :?(\d\d)? # $11: min
81
+ :?(\d\d)? # $12: sec
82
+ \.?(\d+)? # $13: dec
83
+ \s?(?:(a|p)?m)? # $14: am/pm
84
+ \s?(([-+])?(\d\d):?(\d\d)|UTC|GMT)? # $15: offset ($16=sign, $17=hours, $18=mins)
86
85
  !iox
87
- ymd = $1 ? [$3.to_i, month_num($2), $1.to_i] : $4 ? [$4.to_i, $5.to_i, $6.to_i] : [$9.to_i, $7.to_i, $8.to_i]
86
+ ymd = $1 ? [ $3.to_i, month_value($2), $1.to_i] : \
87
+ $4 ? [ $4.to_i, month_value($5), $6.to_i] : \
88
+ [ $9.to_i, month_value($7), $8.to_i]
88
89
  hms = [$14 ? ($10.to_i % 12) + (($14=="P" || $14=="p") ? 12 : 0) : $10.to_i, $11.to_i, "#{$12}.#{$13}".to_f]
89
- off = ($17 ? "#{$16||'+'}#{$17}:#{$18}" : "+00:00") if $15 && !ignore_offset
90
+ off = ($17 ? "#{$16||'+'}#{$17}:#{$18}" : "+00:00") if $15
90
91
  else
91
92
  raise "can't parse: #{str}"
92
93
  end
93
- off ? [ymd, hms, off] : [ymd, hms]
94
- end
95
-
96
- # get month number
97
- def self.month_num(str)
98
- (@month_num ||= {
99
- "jan" => 1, "january" => 1, "jul" => 7, "july" => 7,
100
- "feb" => 2, "february" => 2, "aug" => 8, "august" => 8,
101
- "mar" => 3, "march" => 3, "sep" => 9, "septmeber" => 9,
102
- "apr" => 4, "april" => 4, "oct" => 10, "october" => 10,
103
- "may" => 5, "nov" => 11, "november" => 11,
104
- "jun" => 6, "june" => 6, "dec" => 12, "december" => 12,
105
- })[str.downcase] or raise "bad month: #{str}"
94
+ [ymd, hms, off]
106
95
  end
107
96
 
108
- # parse time and honor desired timezone
109
- def self.to_tz(str, zone=nil, ignore_offset=false)
110
- ymd, hms, off = parse_str(str, ignore_offset)
111
- out = Time.new(*ymd, *hms, off)
112
- if zone
113
- if off
114
- out = out.to_tz(zone)
115
- else
116
- utc = out.utc
117
- off = TZInfo::Timezone.get(zone).utc_to_local(utc) - utc
118
- out = Time.new(*ymd, *hms, off)
119
- end
120
- else
121
- out
122
- end
97
+ def self.tz(str, toz=nil, asz=nil)
98
+ ymd, hms, off = parse_str(str)
99
+ out = Time.new(*ymd, *hms, asz ? TZInfo::Timezone.get(asz) : off)
100
+ toz ? out.to(toz) : out
123
101
  end
124
102
 
125
- # ignore supplied timezone, use local
126
- def self.to_tz!(str, zone=nil)
127
- to_tz(str, zone, true)
103
+ def self.tz!(str, asz="UTC", toz=nil)
104
+ tz(str, toz, asz)
128
105
  end
129
106
 
130
- # NOTE: We can clean this up too...
131
- # this 1-liner works, but returns a TZInfo::TimeWithOffset???
132
- # def in_tz(zone); TZInfo::Timezone.get(zone).to_local(self); end
133
-
134
- # same time moment, different time zone offset
135
- def in_tz(zone)
107
+ # same time moment, different time zone (ie - change time and zone)
108
+ def to(zone)
136
109
  cfg = TZInfo::Timezone.get(zone)
137
110
  use = cfg.to_local(self)
138
111
  ary = use.to_a[1,5].reverse.push(strftime("%S.%6N").to_f)
139
112
  Time.new(*ary, cfg)
140
113
  end
141
114
 
142
- # same time values, different time zone offset
143
- def as_tz(zone)
115
+ # same time values, different time zone (ie - change time zone only)
116
+ def as(zone)
144
117
  cfg = TZInfo::Timezone.get(zone)
145
118
  use = self
146
119
  ary = use.to_a[1,5].reverse.push(strftime("%S.%6N").to_f)
147
120
  Time.new(*ary, cfg)
148
121
  end
149
-
150
- alias_method :to_tz , :in_tz
151
- alias_method :to_tz!, :as_tz
152
122
  end
153
123
 
154
124
  class String
155
- def to_tz(*args)
156
- Time.to_tz(self, *args)
125
+ def to_day
126
+ Date.to_day(self)
157
127
  end
158
128
 
159
- def to_tz!(*args)
160
- Time.to_tz!(self, *args)
129
+ def iso_date(fmt="%Y-%m-%d")
130
+ to_day.strftime(fmt)
161
131
  end
162
132
 
163
- def to_day
164
- Date.to_day(self)
133
+ def to_tz(*args)
134
+ Time.tz(self, *args)
165
135
  end
166
136
 
167
- def to_day!(fmt="%Y-%m-%d")
168
- to_day.strftime(fmt)
137
+ def to_tz!(*args)
138
+ Time.tz!(self, *args)
169
139
  end
170
140
  end
data/zones.gemspec CHANGED
@@ -1,12 +1,10 @@
1
- # encoding: utf-8
2
-
3
1
  Gem::Specification.new do |s|
4
2
  s.name = "zones"
5
- s.version = "0.6.2"
3
+ s.version = "1.0.0"
6
4
  s.author = "Steve Shreeve"
7
5
  s.email = "steve.shreeve@gmail.com"
8
- s.summary = "Easy time parsing and conversion between time zones"
9
- s.description = "This gem makes it easy to work with time zones."
6
+ s.summary =
7
+ s.description = "A friendly Ruby gem for time parsing and time zone conversion"
10
8
  s.homepage = "https://github.com/shreeve/zones"
11
9
  s.license = "MIT"
12
10
  s.files = `git ls-files`.split("\n") - %w[.gitignore]
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zones
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Shreeve
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-27 00:00:00.000000000 Z
11
+ date: 2023-06-29 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: This gem makes it easy to work with time zones.
13
+ description: A friendly Ruby gem for time parsing and time zone conversion
14
14
  email: steve.shreeve@gmail.com
15
15
  executables: []
16
16
  extensions: []
@@ -43,5 +43,5 @@ requirements: []
43
43
  rubygems_version: 3.4.14
44
44
  signing_key:
45
45
  specification_version: 4
46
- summary: Easy time parsing and conversion between time zones
46
+ summary: A friendly Ruby gem for time parsing and time zone conversion
47
47
  test_files: []