vanadiel-time 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +3 -0
- data/.gitignore +5 -0
- data/.rspec +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +4 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +47 -0
- data/Rakefile +34 -0
- data/examples/clock.rb +12 -0
- data/lib/vanadiel/day.rb +29 -0
- data/lib/vanadiel/moon.rb +91 -0
- data/lib/vanadiel/time.rb +533 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/time_spec.rb +682 -0
- data/vanadiel-time.gemspec +26 -0
- metadata +149 -0
data/.document
ADDED
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour --format documentation
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--markup markdown --title "vanadiel-time Documentation" --protected
|
data/ChangeLog.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Yuki
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# vanadiel-time
|
2
|
+
|
3
|
+
* [Homepage](https://github.com/pasela/vanadiel-time-gem)
|
4
|
+
* [Issues](https://github.com/pasela/vanadiel-time-gem/issues)
|
5
|
+
* [Documentation](http://rubydoc.info/gems/vanadiel-time/frames)
|
6
|
+
* [Email](mailto:paselan at gmail.com )
|
7
|
+
|
8
|
+
## Description
|
9
|
+
|
10
|
+
A library for dealing with Vana'diel time from Final Fantasy XI.
|
11
|
+
Converting between realtime and Vana'diel time, and so on.
|
12
|
+
|
13
|
+
## Examples
|
14
|
+
|
15
|
+
require 'vanadiel/time'
|
16
|
+
|
17
|
+
p Vanadiel::Time.now #=> 1156-09-01 10:31:27
|
18
|
+
p Vanadiel::Time.new(1156, 2, 4, 10, 15, 30) #=> 1156-02-04 10:15:30
|
19
|
+
|
20
|
+
Another example:
|
21
|
+
|
22
|
+
require 'vanadiel/time'
|
23
|
+
|
24
|
+
et = Time.now
|
25
|
+
vt = Vanadiel::Time.at(et)
|
26
|
+
|
27
|
+
puts "Earth : %s" % et.strftime("%Y-%m-%d %H:%M:%S %A")
|
28
|
+
puts "Vana'diel: %s" % vt.strftime("%Y-%m-%d %H:%M:%S %A")
|
29
|
+
puts " %s %s (%d%%)" % [Vanadiel::Moon::MOONNAMES_JA[vt.moon_age],
|
30
|
+
Vanadiel::Moon::MOONNAMES[vt.moon_age],
|
31
|
+
vt.moon_percent]
|
32
|
+
|
33
|
+
output:
|
34
|
+
|
35
|
+
Earth : 2012-09-02 02:58:43 Sunday
|
36
|
+
Vana'diel: 1156-08-19 02:28:06 Iceday
|
37
|
+
二十日余月 Waning Crescent (38%)
|
38
|
+
|
39
|
+
## Install
|
40
|
+
|
41
|
+
$ gem install vanadiel-time
|
42
|
+
|
43
|
+
## Copyright
|
44
|
+
|
45
|
+
Copyright (c) 2012 Yuki
|
46
|
+
|
47
|
+
See {file:LICENSE.txt} for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bundler'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e.message
|
9
|
+
warn "Run `gem install bundler` to install Bundler."
|
10
|
+
exit -1
|
11
|
+
end
|
12
|
+
|
13
|
+
begin
|
14
|
+
Bundler.setup(:development)
|
15
|
+
rescue Bundler::BundlerError => e
|
16
|
+
warn e.message
|
17
|
+
warn "Run `bundle install` to install missing gems."
|
18
|
+
exit e.status_code
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rake'
|
22
|
+
|
23
|
+
require 'rubygems/tasks'
|
24
|
+
Gem::Tasks.new
|
25
|
+
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
RSpec::Core::RakeTask.new
|
28
|
+
|
29
|
+
task :test => :spec
|
30
|
+
task :default => :spec
|
31
|
+
|
32
|
+
require 'yard'
|
33
|
+
YARD::Rake::YardocTask.new
|
34
|
+
task :doc => :yard
|
data/examples/clock.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'vanadiel/time'
|
4
|
+
|
5
|
+
et = Time.now
|
6
|
+
vt = Vanadiel::Time.at(et)
|
7
|
+
|
8
|
+
puts "Earth : %s" % et.strftime("%Y-%m-%d %H:%M:%S %A")
|
9
|
+
puts "Vana'diel: %s" % vt.strftime("%Y-%m-%d %H:%M:%S %A")
|
10
|
+
puts " %s %s (%d%%)" % [Vanadiel::Moon::MOONNAMES_JA[vt.moon_age],
|
11
|
+
Vanadiel::Moon::MOONNAMES[vt.moon_age],
|
12
|
+
vt.moon_percent]
|
data/lib/vanadiel/day.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Vanadiel
|
4
|
+
# Vanadiel::Day has some constants about Vana'diel days.
|
5
|
+
module Day
|
6
|
+
# 火曜日
|
7
|
+
FIRESDAY = 0
|
8
|
+
# 土曜日
|
9
|
+
EARTHSDAY = 1
|
10
|
+
# 水曜日
|
11
|
+
WATERSDAY = 2
|
12
|
+
# 風曜日
|
13
|
+
WINDSDAY = 3
|
14
|
+
# 氷曜日
|
15
|
+
ICEDAY = 4
|
16
|
+
# 雷曜日
|
17
|
+
LIGHTNINGDAY = 5
|
18
|
+
# 光曜日
|
19
|
+
LIGHTSDAY = 6
|
20
|
+
# 闇曜日
|
21
|
+
DARKSDAY = 7
|
22
|
+
|
23
|
+
# Day names
|
24
|
+
DAYNAMES = ['Firesday', 'Earthsday', 'Watersday', 'Windsday', 'Iceday', 'Lightningday', 'Lightsday', 'Darksday']
|
25
|
+
|
26
|
+
# Day names for Japanese
|
27
|
+
DAYNAMES_JA = ['火曜日', '土曜日', '水曜日', '風曜日', '氷曜日', '雷曜日', '光曜日', '闇曜日']
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Vanadiel
|
4
|
+
# Vanadiel::Moon has some constants about Vana'diel moon phases (12 steps version).
|
5
|
+
#
|
6
|
+
# moon phase (0..11, for Japanese service)
|
7
|
+
module Moon
|
8
|
+
# 新月
|
9
|
+
NEW_MOON = 0
|
10
|
+
# 三日月
|
11
|
+
WAXING_CRESCENT1 = 1
|
12
|
+
# 七日月
|
13
|
+
WAXING_CRESCENT2 = 2
|
14
|
+
# 上弦の月
|
15
|
+
FIRST_QUARTER = 3
|
16
|
+
# 十日夜
|
17
|
+
WAXING_GIBBOUS1 = 4
|
18
|
+
# 十三夜
|
19
|
+
WAXING_GIBBOUS2 = 5
|
20
|
+
# 満月
|
21
|
+
FULL_MOON = 6
|
22
|
+
# 十六夜
|
23
|
+
WANING_GIBBOUS1 = 7
|
24
|
+
# 居待月
|
25
|
+
WANING_GIBBOUS2 = 8
|
26
|
+
# 下弦の月
|
27
|
+
LAST_QUARTER = 9
|
28
|
+
# 二十日余月
|
29
|
+
WANING_CRESCENT1 = 10
|
30
|
+
# 二十六夜
|
31
|
+
WANING_CRESCENT2 = 11
|
32
|
+
|
33
|
+
# Moon phase names
|
34
|
+
MOONNAMES = [
|
35
|
+
'New Moon',
|
36
|
+
'Waxing Crescent',
|
37
|
+
'Waxing Crescent',
|
38
|
+
'First Quarter',
|
39
|
+
'Waxing Gibbous',
|
40
|
+
'Waxing Gibbous',
|
41
|
+
'Full Moon',
|
42
|
+
'Waning Gibbous',
|
43
|
+
'Waning Gibbous',
|
44
|
+
'Last Quarter',
|
45
|
+
'Waning Crescent',
|
46
|
+
'Waning Crescent',
|
47
|
+
]
|
48
|
+
|
49
|
+
# Moon phase names for Japanese
|
50
|
+
MOONNAMES_JA = [
|
51
|
+
'新月',
|
52
|
+
'三日月',
|
53
|
+
'七日月',
|
54
|
+
'上弦の月',
|
55
|
+
'十日夜',
|
56
|
+
'十三夜',
|
57
|
+
'満月',
|
58
|
+
'十六夜',
|
59
|
+
'居待月',
|
60
|
+
'下弦の月',
|
61
|
+
'二十日余月',
|
62
|
+
'二十六夜',
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
# Vanadiel::Moon7 has some constants about Vana'diel moon phases (8 steps version).
|
67
|
+
#
|
68
|
+
# moon phase (0..7, for Non-Japanese service)
|
69
|
+
module Moon7
|
70
|
+
NEW_MOON = 0
|
71
|
+
WAXING_CRESCENT = 1
|
72
|
+
FIRST_QUARTER = 2
|
73
|
+
WAXING_GIBBOUS = 3
|
74
|
+
FULL_MOON = 4
|
75
|
+
WANING_GIBBOUS = 5
|
76
|
+
LAST_QUARTER = 6
|
77
|
+
WANING_CRESCENT = 7
|
78
|
+
|
79
|
+
# Moon phase names
|
80
|
+
MOONNAMES = [
|
81
|
+
'New Moon',
|
82
|
+
'Waxing Crescent',
|
83
|
+
'First Quarter',
|
84
|
+
'Waxing Gibbous',
|
85
|
+
'Full Moon',
|
86
|
+
'Waning Gibbous',
|
87
|
+
'Last Quarter',
|
88
|
+
'Waning Crescent',
|
89
|
+
]
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,533 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'vanadiel/day'
|
4
|
+
require 'vanadiel/moon'
|
5
|
+
|
6
|
+
module Vanadiel
|
7
|
+
# Vanadiel::Time is an abstraction of Vana'diel dates and times from Final Fantasy XI.
|
8
|
+
# Time is stored internally as the number of microseconds since C.E. 0001-01-01 00:00:00.
|
9
|
+
#
|
10
|
+
# Vana'diel time spec:
|
11
|
+
#
|
12
|
+
# One year = 12 months = 360 days
|
13
|
+
# One month = 30 days
|
14
|
+
# One day = 24 hours
|
15
|
+
# One hour = 60 minutes
|
16
|
+
# One minute = 60 seconds
|
17
|
+
# One second = 0.04 seconds of the earth's (1/25th of a second)
|
18
|
+
#
|
19
|
+
# Vana'diel second = 0.04 earth seconds (1/25th of a second)
|
20
|
+
# Vana'diel minute = 2.4 earth seconds
|
21
|
+
# Vana'diel hour = 2 minutes 24 earth seconds
|
22
|
+
# Vana'diel day = 57 minutes 36 earth seconds
|
23
|
+
# Vana'diel week = 7 hours 40 minutes 48 earth seconds
|
24
|
+
# Vana'diel calendar month = 1 day 4 hours 48 earth minutes
|
25
|
+
# Vana'diel lunar month = 3 days 14 hours 24 earth minutes
|
26
|
+
# Vana'diel year = 14 days 9 hours 36 earth minutes
|
27
|
+
#
|
28
|
+
# Each full lunar cycle lasts for 84 Vana'diel days.
|
29
|
+
# Vana'diel has 12 distinct moon phases.
|
30
|
+
# Japanese client expresses moon phases by 12 kinds of texts. (percentage is not displayed in Japanese client)
|
31
|
+
# Non-Japanese client expresses moon phases by 7 kinds of texts and percentage.
|
32
|
+
#
|
33
|
+
# C.E. = Crystal Era
|
34
|
+
#
|
35
|
+
# A.D. -91270800 => 1967/02/10 00:00:00 +0900
|
36
|
+
# C.E. 0 => 0001/01/01 00:00:00
|
37
|
+
#
|
38
|
+
# A.D. 2002/01/01(Tue) 00:00:00 JST
|
39
|
+
# C.E. 0886/01/01(Fir) 00:00:00
|
40
|
+
#
|
41
|
+
# A.D. 2047/10/22(Tue) 01:00:00 JST
|
42
|
+
# C.E. 2047/10/22(Wat) 01:00:00
|
43
|
+
#
|
44
|
+
# A.D. 2047/10/21(Mon) 15:37:30 UTC
|
45
|
+
# C.E. 2047/10/21(Win) 15:37:30
|
46
|
+
class Time
|
47
|
+
# vanadiel-time version
|
48
|
+
VERSION = "0.1.0"
|
49
|
+
|
50
|
+
ONE_SECOND = 1000000
|
51
|
+
ONE_MINUTE = 60 * ONE_SECOND
|
52
|
+
ONE_HOUR = 60 * ONE_MINUTE
|
53
|
+
ONE_DAY = 24 * ONE_HOUR
|
54
|
+
ONE_WEEK = 8 * ONE_DAY
|
55
|
+
ONE_MONTH = 30 * ONE_DAY
|
56
|
+
ONE_YEAR = 360 * ONE_DAY
|
57
|
+
|
58
|
+
VANA_TIME_SCALE = 25 # Vana'diel time goes 25 times faster than the Earth
|
59
|
+
VANA_BASE_YEAR = 886
|
60
|
+
VANA_BASE_TIME = (VANA_BASE_YEAR * ONE_YEAR) / VANA_TIME_SCALE
|
61
|
+
EARTH_BASE_TIME = 1009810800 * ONE_SECOND # 2002/01/01 00:00:00.000 JST
|
62
|
+
DIFF_TIME = VANA_BASE_TIME - EARTH_BASE_TIME
|
63
|
+
MOON_CYCLE_DAYS = 84 # Vana'diel moon cycle lasts 84 days
|
64
|
+
|
65
|
+
# @return [Bignum] the value of the time as microseconds since C.E. 0001-01-01 00:00:00
|
66
|
+
attr_reader :time
|
67
|
+
|
68
|
+
# @return [Fixnum] the year for time
|
69
|
+
attr_reader :year
|
70
|
+
|
71
|
+
# @return [Fixnum] the month of the year (1..12) for time
|
72
|
+
attr_reader :month
|
73
|
+
|
74
|
+
# @return [Fixnum] the month of the year (1..12) for time
|
75
|
+
alias_method :mon, :month
|
76
|
+
|
77
|
+
# @return [Fixnum] the day of the month (1..30) for time
|
78
|
+
attr_reader :mday
|
79
|
+
alias_method :day, :mday
|
80
|
+
|
81
|
+
# @return [Fixnum] the hour of the day (0..23) for time
|
82
|
+
attr_reader :hour
|
83
|
+
|
84
|
+
# @return [Fixnum] the minute of the hour (0..59) for time
|
85
|
+
attr_reader :min
|
86
|
+
|
87
|
+
# @return [Fixnum] the second of the minute (0..59) for time
|
88
|
+
attr_reader :sec
|
89
|
+
|
90
|
+
# @return [Fixnum] just the number of microseconds (0..999999) for time
|
91
|
+
attr_reader :usec
|
92
|
+
|
93
|
+
# @return [Fixnum] an integer representing the day of the week, 0..7, with Firesday == 0
|
94
|
+
attr_reader :wday
|
95
|
+
|
96
|
+
# @return [Fixnum] an integer representing the day of the year (1..360)
|
97
|
+
attr_reader :yday
|
98
|
+
|
99
|
+
# @return [Fixnum] an integer representing the moon age (0..11), for Japanese service
|
100
|
+
attr_reader :moon_age
|
101
|
+
alias_method :moon_age12, :moon_age
|
102
|
+
|
103
|
+
# @return [Fixnum] an integer representing the moon age (0..7), for Non-Japanese service
|
104
|
+
attr_reader :moon_age7
|
105
|
+
|
106
|
+
# @return [Fixnum] an integer representing the moon phase percentage (0..100), for Non-Japanese service
|
107
|
+
attr_reader :moon_percent
|
108
|
+
|
109
|
+
# @return [Fixnum] the number of microseconds of the moon
|
110
|
+
attr_reader :time_of_moon
|
111
|
+
|
112
|
+
# It is initialized to the current time if no argument.
|
113
|
+
# If one or more arguments specified, the time is initialized to the specified time.
|
114
|
+
#
|
115
|
+
# @overload new()
|
116
|
+
# It is initialized to the current time if no argument.
|
117
|
+
# @overload new(year, mon = 1, day = 1, hour = 0, min = 0, sec = 0, usec = 0)
|
118
|
+
# If one or more arguments specified, the time is initialized to the specified time.
|
119
|
+
# @param [Integer] year the year part (1..n)
|
120
|
+
# @param [Integer] mon the month part (1..12)
|
121
|
+
# @param [Integer] day the day of month part (1..30)
|
122
|
+
# @param [Integer] hour the hour part (0..23)
|
123
|
+
# @param [Integer] min the minute part (0..59)
|
124
|
+
# @param [Integer] sec the second part (0..59)
|
125
|
+
# @param [Integer] usec the microsecond part (0..999999)
|
126
|
+
def initialize(*args)
|
127
|
+
self.time = args.empty? ? self.class.earth_to_vana(::Time.now.to_f * ONE_SECOND) : self.class.ymdhms_to_usec(*args)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Synonym for Vanadiel::Time.new. Returns a new time object initialized to the current time.
|
131
|
+
#
|
132
|
+
# @return [Vanadiel::Time] the time object initialized to the current time.
|
133
|
+
def self.now
|
134
|
+
self.new
|
135
|
+
end
|
136
|
+
|
137
|
+
# Same as Vanadiel::Time.new, but the year is required.
|
138
|
+
#
|
139
|
+
# @return [Vanadiel::Time] the time object initialized to the specified time.
|
140
|
+
def self.mktime(year, *rest_part)
|
141
|
+
args = [year, *rest_part]
|
142
|
+
self.new(*args)
|
143
|
+
end
|
144
|
+
|
145
|
+
# Creates a new time object with the value given by time.
|
146
|
+
#
|
147
|
+
# @overload at(time)
|
148
|
+
# @param [::Time, Vanadiel::Time] time the time object
|
149
|
+
# @return [Vanadiel::Time] the time object initialized to the specified time.
|
150
|
+
# @overload at(seconds, usec = 0)
|
151
|
+
# @param [Integer, Float] sec seconds from C.E. 0001-01-01 00:00:00
|
152
|
+
# @param [Integer] usec the microseconds
|
153
|
+
# @return [Vanadiel::Time] the time object initialized to the specified time.
|
154
|
+
def self.at(time, usec = 0)
|
155
|
+
obj = self.new
|
156
|
+
if time.is_a? ::Time
|
157
|
+
obj.time = self.earth_to_vana(time.to_f * ONE_SECOND)
|
158
|
+
elsif time.is_a?(Vanadiel::Time)
|
159
|
+
obj.time = time.time
|
160
|
+
elsif time.is_a?(Integer) || time.is_a?(Float)
|
161
|
+
obj.time = ((time * ONE_SECOND) + usec).to_i
|
162
|
+
else
|
163
|
+
raise ArgumentError, 'invalid argument'
|
164
|
+
end
|
165
|
+
obj
|
166
|
+
end
|
167
|
+
|
168
|
+
# Converts microseconds as Vana'diel time to microseconds as the Earth time from the Epoch.
|
169
|
+
#
|
170
|
+
# @param [Integer] vana_time microseconds as Vana'diel time
|
171
|
+
# @return [Integer] microseconds as the Earth time
|
172
|
+
def self.vana_to_earth(vana_time)
|
173
|
+
earth = (((vana_time + ONE_YEAR) / VANA_TIME_SCALE) - DIFF_TIME)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Converts microseconds as the Earth time to microseconds as Vana'diel time from the Epoch.
|
177
|
+
#
|
178
|
+
# @param [Integer] earth_time microseconds as the Earth time
|
179
|
+
# @return [Integer] microseconds as Vana'diel time
|
180
|
+
def self.earth_to_vana(earth_time)
|
181
|
+
(earth_time + DIFF_TIME) * VANA_TIME_SCALE - ONE_YEAR
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns true if time represents Firesday.
|
185
|
+
#
|
186
|
+
# @return [Boolean] true if Firesday
|
187
|
+
def firesday?; @wday == Vanadiel::Day::FIRESDAY; end
|
188
|
+
|
189
|
+
# Returns true if time represents Earthsday.
|
190
|
+
#
|
191
|
+
# @return [Boolean] true if Earthsday
|
192
|
+
def earthsday?; @wday == Vanadiel::Day::EARTHSDAY; end
|
193
|
+
|
194
|
+
# Returns true if time represents Watersday.
|
195
|
+
#
|
196
|
+
# @return [Boolean] true if Watersday
|
197
|
+
def watersday?; @wday == Vanadiel::Day::WATERSDAY; end
|
198
|
+
|
199
|
+
# Returns true if time represents Windsday.
|
200
|
+
#
|
201
|
+
# @return [Boolean] true if Windsday
|
202
|
+
def windsday?; @wday == Vanadiel::Day::WINDSDAY; end
|
203
|
+
|
204
|
+
# Returns true if time represents Iceday.
|
205
|
+
#
|
206
|
+
# @return [Boolean] true if Iceday
|
207
|
+
def iceday?; @wday == Vanadiel::Day::ICEDAY; end
|
208
|
+
|
209
|
+
# Returns true if time represents Lightningday.
|
210
|
+
#
|
211
|
+
# @return [Boolean] true if Lightningday
|
212
|
+
def lightningday?; @wday == Vanadiel::Day::LIGHTNINGDAY; end
|
213
|
+
|
214
|
+
# Returns true if time represents Lightsday.
|
215
|
+
#
|
216
|
+
# @return [Boolean] true if Lightsday
|
217
|
+
def lightsday?; @wday == Vanadiel::Day::LIGHTSDAY; end
|
218
|
+
|
219
|
+
# Returns true if time represents Darksday.
|
220
|
+
#
|
221
|
+
# @return [Boolean] true if Darksday
|
222
|
+
def darksday?; @wday == Vanadiel::Day::DARKSDAY; end
|
223
|
+
|
224
|
+
# Format Vana'diel time according to the directives in the format string.
|
225
|
+
# The directives begins with a percent (%) character. Any text not listed
|
226
|
+
# as a directive will be passed through to the output string.
|
227
|
+
#
|
228
|
+
# The directive consists of a percent (%) character, zero or more flags,
|
229
|
+
# optional minimum field width and a conversion specifier as follows.
|
230
|
+
#
|
231
|
+
# %<flags><width><conversion>
|
232
|
+
#
|
233
|
+
# Flags:
|
234
|
+
#
|
235
|
+
# - don't pad a numerical output.
|
236
|
+
# _ use spaces for padding.
|
237
|
+
# 0 use zeros for padding.
|
238
|
+
# ^ upcase the result string.
|
239
|
+
# # change case.
|
240
|
+
#
|
241
|
+
# The minimum field width specifies the minimum width.
|
242
|
+
#
|
243
|
+
# Format directives:
|
244
|
+
#
|
245
|
+
# Date (Year, Month, Day):
|
246
|
+
# %Y - Year with century (can be negative)
|
247
|
+
# -0001, 0000, 1995, 2009, 14292, etc.
|
248
|
+
# %C - year / 100 (round down. 20 in 2009)
|
249
|
+
# %y - year % 100 (00..99)
|
250
|
+
#
|
251
|
+
# %m - Month of the year, zero-padded (01..12)
|
252
|
+
# %_m blank-padded ( 1..12)
|
253
|
+
# %-m no-padded (1..12)
|
254
|
+
#
|
255
|
+
# %d - Day of the month, zero-padded (01..30)
|
256
|
+
# %-d no-padded (1..30)
|
257
|
+
# %e - Day of the month, blank-padded ( 1..30)
|
258
|
+
#
|
259
|
+
# %j - Day of the year (001..360)
|
260
|
+
#
|
261
|
+
# Time (Hour, Minute, Second, Subsecond):
|
262
|
+
# %H - Hour of the day, 24-hour clock, zero-padded (00..23)
|
263
|
+
# %k - Hour of the day, 24-hour clock, blank-padded ( 0..23)
|
264
|
+
#
|
265
|
+
# %M - Minute of the hour (00..59)
|
266
|
+
#
|
267
|
+
# %S - Second of the minute (00..59)
|
268
|
+
#
|
269
|
+
# %L - Millisecond of the second (000..999)
|
270
|
+
# %N - Fractional seconds digits, default is 6 digits (microsecond)
|
271
|
+
# %3N millisecond (3 digits)
|
272
|
+
# %6N microsecond (6 digits)
|
273
|
+
#
|
274
|
+
# Weekday:
|
275
|
+
# %A - The full weekday name (``Firesday'')
|
276
|
+
# %^A uppercased (``FIRESDAY'')
|
277
|
+
# %w - Day of the week (Firesday is 0, 0..7)
|
278
|
+
#
|
279
|
+
# Seconds since the Epoch:
|
280
|
+
# %s - Number of seconds since 0001-01-01 00:00:00
|
281
|
+
#
|
282
|
+
# Literal string:
|
283
|
+
# %n - Newline character (\n)
|
284
|
+
# %t - Tab character (\t)
|
285
|
+
# %% - Literal ``%'' character
|
286
|
+
#
|
287
|
+
# Combination:
|
288
|
+
# %F - The ISO 8601 date format (%Y-%m-%d)
|
289
|
+
# %X - Same as %T
|
290
|
+
# %R - 24-hour time (%H:%M)
|
291
|
+
# %T - 24-hour time (%H:%M:%S)
|
292
|
+
#
|
293
|
+
# @param [String] format the format string
|
294
|
+
# @return [String] formatted string
|
295
|
+
def strftime(format)
|
296
|
+
source = { 'Y' => @year, 'C' => @year / 100, 'y' => @year % 100,
|
297
|
+
'm' => @month, 'd' => @mday, 'e' => @mday, 'j' => @yday,
|
298
|
+
'H' => @hour, 'k' => @hour, 'M' => @min, 'S' => @sec, 'L' => @usec, 'N' => @usec,
|
299
|
+
'A' => @wday, 'w' => @wday, 's' => @time,
|
300
|
+
'n' => "\n", 't' => "\t", '%' => '%' }
|
301
|
+
default_padding = { 'e' => ' ', 'k' => ' ', 'A' => ' ', 'n' => ' ', 't' => ' ', '%' => ' ' }
|
302
|
+
default_padding.default = '0'
|
303
|
+
default_width = { 'y' => 2, 'm' => 2, 'd' => 2, 'e' => 2, 'H' => 2, 'k' => 2, 'M' => 2, 'S' => 2,
|
304
|
+
'j' => 3, 'L' => 3,
|
305
|
+
'N' => 6 }
|
306
|
+
default_width.default = 0
|
307
|
+
|
308
|
+
format.gsub(/%([-_0^#]+)?(\d+)?([FXRT])/) {
|
309
|
+
case $3
|
310
|
+
when 'F' then '%Y-%m-%d'
|
311
|
+
when 'T', 'X' then '%H:%M:%S'
|
312
|
+
when 'R' then '%H:%M'
|
313
|
+
end
|
314
|
+
}.gsub(/%([-_0^#]+)?(\d+)?([YCymdejHkMSLNAawsnt%])/) {|s|
|
315
|
+
flags = $1; width = $2.to_i; conversion = $3; upcase = false
|
316
|
+
padding = default_padding[conversion]
|
317
|
+
width = default_width[conversion] if width.zero?
|
318
|
+
v = source[conversion]
|
319
|
+
|
320
|
+
flags.each_char {|c|
|
321
|
+
case c
|
322
|
+
when '-' then padding = nil
|
323
|
+
when '_' then padding = ' '
|
324
|
+
when '0' then padding = '0'
|
325
|
+
when '^', '#' then upcase = true
|
326
|
+
end
|
327
|
+
} if flags
|
328
|
+
|
329
|
+
case conversion
|
330
|
+
when 'L', 'N'
|
331
|
+
if (width <= 6)
|
332
|
+
v = v / (100000 / (10 ** (width - 1)))
|
333
|
+
else
|
334
|
+
v = v * (10 ** (width - 6))
|
335
|
+
end
|
336
|
+
when 'A'
|
337
|
+
v = Vanadiel::Day::DAYNAMES[v]
|
338
|
+
end
|
339
|
+
|
340
|
+
v = v.to_s
|
341
|
+
if width > 0 && padding && v.length < width
|
342
|
+
v = (padding * (width - v.length)) + v
|
343
|
+
end
|
344
|
+
|
345
|
+
upcase ? v.upcase : v
|
346
|
+
}
|
347
|
+
end
|
348
|
+
|
349
|
+
# Adds some number of seconds (possibly fractional) to time and returns that value as a new time.
|
350
|
+
#
|
351
|
+
# @param [Integer, Float] sec seconds
|
352
|
+
# @return [Vanadiel::Time] new time
|
353
|
+
def +(sec)
|
354
|
+
self.class.at((@time + (sec * ONE_SECOND)) / ONE_SECOND)
|
355
|
+
end
|
356
|
+
|
357
|
+
# Returns a new time that represents the difference between two times,
|
358
|
+
# or subtracts the given number of seconds in numeric from time.
|
359
|
+
#
|
360
|
+
# @overload -(time)
|
361
|
+
# Returns a new time that represents the difference between two times.
|
362
|
+
# @param [::Time, Vanadiel::Time] other_time the other time object
|
363
|
+
# @return [Float] seconds that represents the difference
|
364
|
+
# @overload -(seconds)
|
365
|
+
# Subtracts the given number of seconds in numeric from time.
|
366
|
+
# @param [Integer, Float] sec seconds
|
367
|
+
# @return [Vanadiel::Time] new time
|
368
|
+
def -(time)
|
369
|
+
if time.is_a? ::Time
|
370
|
+
(@time.to_f - self.class.earth_to_vana(time.to_f * ONE_SECOND)) / ONE_SECOND
|
371
|
+
elsif time.is_a?(Vanadiel::Time)
|
372
|
+
(@time.to_f - time.time) / ONE_SECOND
|
373
|
+
elsif time.is_a?(Integer) || time.is_a?(Float)
|
374
|
+
self.class.at((@time / ONE_SECOND) - time)
|
375
|
+
else
|
376
|
+
raise ArgumentError, 'invalid argument'
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
# Compares time with other time.
|
381
|
+
#
|
382
|
+
# @param [Vanadiel::Time] other_time the other time
|
383
|
+
# @return [-1] if the time is earlier than the other time.
|
384
|
+
# @return [0] if the time is same as the other time.
|
385
|
+
# @return [1] if the time is later than the other time.
|
386
|
+
# @return [nil] if it cannot compare.
|
387
|
+
def <=>(other_time)
|
388
|
+
@time <=> other_time.time
|
389
|
+
end
|
390
|
+
|
391
|
+
# Returns the value of time as a floating point number of seconds since C.E. 0001-01-01 00:00:00.
|
392
|
+
#
|
393
|
+
# @return [Float] seconds
|
394
|
+
def to_i
|
395
|
+
@time / ONE_SECOND
|
396
|
+
end
|
397
|
+
|
398
|
+
# Returns the value of time as an integer number of seconds since C.E. 0001-01-01 00:00:00.
|
399
|
+
#
|
400
|
+
# @return [Integer] seconds
|
401
|
+
def to_f
|
402
|
+
@time.to_f / ONE_SECOND
|
403
|
+
end
|
404
|
+
|
405
|
+
# Returns a string representing time. Equivalent to calling #strftime with
|
406
|
+
# a format string of "%Y-%m-%d %H:%M:%S".
|
407
|
+
#
|
408
|
+
# @return [String] the string representing time
|
409
|
+
def to_s
|
410
|
+
self.strftime('%Y-%m-%d %H:%M:%S')
|
411
|
+
end
|
412
|
+
|
413
|
+
# Returns the value of time as the Earth time object.
|
414
|
+
#
|
415
|
+
# @return [::Time] the Earth time object
|
416
|
+
def to_earth_time
|
417
|
+
::Time.at(self.class.vana_to_earth(@time) / ONE_SECOND)
|
418
|
+
end
|
419
|
+
|
420
|
+
# Returns a hash code for this time object.
|
421
|
+
#
|
422
|
+
# @return [Fixnum] the hash code
|
423
|
+
def hash; @time.hash ^ self.class.hash; end
|
424
|
+
|
425
|
+
# Returns true if time and other time are the same time.
|
426
|
+
#
|
427
|
+
# @return [Boolean] true if same
|
428
|
+
def ==(other); @time == other.time; end
|
429
|
+
|
430
|
+
# Returns true if time and other time are both Vanadiel::Time objects with the same time.
|
431
|
+
#
|
432
|
+
# @return [Boolean] true if same
|
433
|
+
def eql?(other); self.hash == other.hash; end
|
434
|
+
|
435
|
+
# Manually sets the time and recompute all fields.
|
436
|
+
#
|
437
|
+
# @param [Integer] time an integer number of microseconds
|
438
|
+
# @note This accessor is used internally.
|
439
|
+
def time=(time)
|
440
|
+
@time = time
|
441
|
+
compute_fields
|
442
|
+
end
|
443
|
+
|
444
|
+
def marshal_dump
|
445
|
+
@time
|
446
|
+
end
|
447
|
+
|
448
|
+
def marshal_load(obj)
|
449
|
+
self.time = obj
|
450
|
+
end
|
451
|
+
|
452
|
+
# Converts to the value of time as an integer number of microseconds since C.E. 0001-01-01 00:00:00.
|
453
|
+
#
|
454
|
+
# @param [Integer] year the year part (1..n)
|
455
|
+
# @param [Integer] mon the month part (1..12)
|
456
|
+
# @param [Integer] day the day of month part (1..30)
|
457
|
+
# @param [Integer] hour the hour part (0..23)
|
458
|
+
# @param [Integer] min the minute part (0..59)
|
459
|
+
# @param [Integer] sec the second part (0..59)
|
460
|
+
# @param [Integer] usec the microsecond part (0..999999)
|
461
|
+
# @return [Integer] microseconds as Vana'diel time
|
462
|
+
def self.ymdhms_to_usec(year, mon = 1, day = 1, hour = 0, min = 0, sec = 0, usec = 0)
|
463
|
+
raise ArgumentError, 'year out of range' if year < 0
|
464
|
+
raise ArgumentError, 'mon out of range' if mon < 1 || mon > 12
|
465
|
+
raise ArgumentError, 'day out of range' if day < 1 || day > 30
|
466
|
+
raise ArgumentError, 'hour out of range' if hour < 0 || hour > 23
|
467
|
+
raise ArgumentError, 'min out of range' if min < 0 || min > 59
|
468
|
+
raise ArgumentError, 'sec out of range' if sec < 0 || sec > 59
|
469
|
+
raise ArgumentError, 'usec out of range' if usec < 0 || usec > 999999
|
470
|
+
((year - 1) * ONE_YEAR) + ((mon - 1) * ONE_MONTH) + ((day - 1) * ONE_DAY) + (hour * ONE_HOUR) + (min * ONE_MINUTE) + (sec * ONE_SECOND) + usec
|
471
|
+
end
|
472
|
+
|
473
|
+
private
|
474
|
+
|
475
|
+
# Computes fields by its value of time.
|
476
|
+
def compute_fields
|
477
|
+
@year = (@time / ONE_YEAR).floor + 1
|
478
|
+
@month = (@time % ONE_YEAR / ONE_MONTH).floor + 1
|
479
|
+
@mday = (@time % ONE_MONTH / ONE_DAY).floor + 1
|
480
|
+
@hour = (@time % ONE_DAY / ONE_HOUR).floor
|
481
|
+
@min = (@time % ONE_HOUR / ONE_MINUTE).floor
|
482
|
+
@sec = (@time % ONE_MINUTE / ONE_SECOND).floor
|
483
|
+
@usec = (@time % ONE_SECOND).floor
|
484
|
+
|
485
|
+
@wday = (@time % ONE_WEEK / ONE_DAY).floor
|
486
|
+
@yday = ((@month - 1) * 30) + @mday
|
487
|
+
|
488
|
+
# MOON_BASE_TIME = 0 - (ONE_DAY * 12) # Start of New moon (10%)
|
489
|
+
#
|
490
|
+
# moon_time = @time - MOON_BASE_TIME
|
491
|
+
# @moon_age = (moon_time / ONE_DAY / 7 % (MAX_MOON_AGE + 1)).floor
|
492
|
+
# @time_of_moon = ((moon_time / ONE_DAY % 7) * ONE_DAY).floor
|
493
|
+
# + (@hour * ONE_HOUR)
|
494
|
+
# + (@min * ONE_MINUTE)
|
495
|
+
# + (@sec * ONE_SECOND)
|
496
|
+
# + (@usec)
|
497
|
+
|
498
|
+
# C.E. 0001/01/01 00:00:00 => WXC 19%
|
499
|
+
# C.E. 0886/01/01 00:00:00 => NM 10%
|
500
|
+
#
|
501
|
+
# 0% NM 7% WXC 40% FQM 57% WXG 90% FM 93% WNG 60% LQM 43% WNC 10% NM
|
502
|
+
# 2% NM 10% WXC 43% FQM 60% WXG 93% FM 90% WNG 57% LQM 40% WNC 7% NM
|
503
|
+
# 5% NM 12% WXC 45% FQM 62% WXG 95% FM 88% WNG 55% LQM 38% WNC 5% NM
|
504
|
+
# 14% WXC 48% FQM 64% WXG 98% FM 86% WNG 52% LQM 36% WNC 2% NM
|
505
|
+
# 17% WXC 50% FQM 67% WXG 100% FM 83% WNG 50% LQM 33% WNC
|
506
|
+
# 19% WXC 52% FQM 69% WXG 98% FM 81% WNG 48% LQM 31% WNC
|
507
|
+
# 21% WXC 55% FQM 71% WXG 95% FM 79% WNG 45% LQM 29% WNC
|
508
|
+
# 24% WXC 74% WXG 76% WNG 26% WNC
|
509
|
+
# 26% WXC 76% WXG 74% WNG 24% WNC
|
510
|
+
# 29% WXC 79% WXG 71% WNG 21% WNC
|
511
|
+
# 31% WXC 81% WXG 69% WNG 19% WNC
|
512
|
+
# 33% WXC 83% WXG 67% WNG 17% WNC
|
513
|
+
# 36% WXC 86% WXG 64% WNG 14% WNC
|
514
|
+
# 38% WXC 88% WXG 62% WNG 12% WNC
|
515
|
+
days = (@time / ONE_DAY).floor
|
516
|
+
@moon_percent = (((days + 8) % MOON_CYCLE_DAYS) * (200.0 / MOON_CYCLE_DAYS)).round
|
517
|
+
@moon_percent = 200 - @moon_percent if @moon_percent > 100
|
518
|
+
|
519
|
+
@moon_age = ((days + 12) / 7) % 12
|
520
|
+
@moon_age7 = case @moon_age
|
521
|
+
when 0 then 0
|
522
|
+
when 1, 2 then 1
|
523
|
+
when 3 then 2
|
524
|
+
when 4, 5 then 3
|
525
|
+
when 6 then 4
|
526
|
+
when 7, 8 then 5
|
527
|
+
when 9 then 6
|
528
|
+
when 10, 11 then 7
|
529
|
+
end
|
530
|
+
@time_of_moon = (((days + 12) % 7) * ONE_DAY) + (@hour * ONE_HOUR) + (@min * ONE_MINUTE) + (@sec * ONE_SECOND) + @usec
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|