Skip to content

Commit 0cd828d

Browse files
Merge pull request #120 from shen-tian/master
Add weekyear/week functionality
2 parents 6b9f9dc + b279f9a commit 0cd828d

File tree

6 files changed

+125
-38
lines changed

6 files changed

+125
-38
lines changed

src/cljs_time/core.cljs

+11-3
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ true
7777
ceorce date-times to or from other types, see cljs-time.coerce."
7878
(:refer-clojure :exclude [= extend second])
7979
(:require
80-
[cljs-time.internal.core :as internal :refer [leap-year? format]]
80+
[cljs-time.internal.core :as internal :refer [leap-year? format
81+
get-week-year]]
8182
[clojure.string :as string]
8283
goog.date.Interval
8384
goog.date)
@@ -118,7 +119,8 @@ expected."}
118119
(minus- [this period] "Returns a new date/time corresponding to the given date/time moved backwards by the given Period(s).")
119120
(first-day-of-the-month- [this] "Returns the first day of the month")
120121
(last-day-of-the-month- [this] "Returns the last day of the month")
121-
(week-number-of-year [this] "Returs the number of weeks in the year"))
122+
(week-number-of-year [this] "Returns the week of the week based year of the given date/time")
123+
(week-year [this] "Returns the the week based year of the given date/time."))
122124

123125
(defprotocol InTimeUnitProtocol
124126
"Interface for in-<time unit> functions"
@@ -211,6 +213,8 @@ expected."}
211213
(week-number-of-year [this]
212214
(goog.date/getWeekNumber
213215
(.getYear this) (.getMonth this) (.getDate this)))
216+
(week-year [this]
217+
(get-week-year (.getYear this) (.getMonth this) (.getDate this)))
214218

215219
goog.date.DateTime
216220
(year [this] (.getYear this))
@@ -235,6 +239,8 @@ expected."}
235239
(week-number-of-year [this]
236240
(goog.date/getWeekNumber
237241
(.getYear this) (.getMonth this) (.getDate this)))
242+
(week-year [this]
243+
(get-week-year (.getYear this) (.getMonth this) (.getDate this)))
238244

239245
goog.date.Date
240246
(year [this] (.getYear this))
@@ -258,7 +264,9 @@ expected."}
258264
(period :days 1)))
259265
(week-number-of-year [this]
260266
(goog.date/getWeekNumber
261-
(.getYear this) (.getMonth this) (.getDate this))))
267+
(.getYear this) (.getMonth this) (.getDate this)))
268+
(week-year [this]
269+
(get-week-year (.getYear this) (.getMonth this) (.getDate this))))
262270

263271
(def utc #js {:id "UTC" :std_offset 0 :names ["UTC"] :transitions []})
264272

src/cljs_time/internal/core.cljs

+31-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
(:require
44
[clojure.string :as string]
55
[goog.string :as gstring]
6-
[goog.string.format]))
6+
[goog.string.format]
7+
[goog.date]))
78

89
(def months
910
["January" "February" "March" "April" "May" "June" "July" "August"
@@ -36,7 +37,8 @@
3637
(and (leap-year? year) (= month 2)) inc))
3738

3839
(defn valid-date?
39-
[{:keys [years months days hours minutes seconds millis] :as d}]
40+
[{:keys [years months days hours minutes seconds millis
41+
weekyear weekyear-week day-of-week] :as d}]
4042
(let [months? (when months (<= 1 months 12))
4143
dim (if years
4244
(and months months? (year-corrected-dim years months))
@@ -45,11 +47,20 @@
4547
hours? (when hours (<= 0 hours 23))
4648
minutes? (when minutes (<= 0 minutes 59))
4749
seconds? (when seconds (<= 0 seconds 60))
48-
millis? (when millis (<= 0 millis 999))]
49-
(if (->> [months? days? hours? minutes? seconds? millis?]
50+
millis? (when millis (<= 0 millis 999))
51+
weekyear-week? (when weekyear-week (<= 1 weekyear-week 53))
52+
day-of-week? (when day-of-week (<= 1 day-of-week 7))]
53+
(if (->> [months? days? hours? minutes? seconds? millis?
54+
weekyear-week? day-of-week?]
5055
(remove nil?)
5156
(every? true?))
52-
d
57+
(if (not (and (or years months days)
58+
(or weekyear weekyear-week day-of-week)))
59+
d
60+
(throw
61+
(ex-info "Mixing year, month, day and week-year week-number fields"
62+
{:type :invalid-date :date d
63+
:errors {}})))
5364
(throw
5465
(ex-info "Date is not valid"
5566
{:type :invalid-date :date d
@@ -59,7 +70,9 @@
5970
(false? hours?) (assoc :hours hours)
6071
(false? minutes?) (assoc :minutes minutes)
6172
(false? seconds?) (assoc :seconds seconds)
62-
(false? millis?) (assoc :millis millis))})))))
73+
(false? millis?) (assoc :millis millis)
74+
(false? weekyear-week?) (assoc :weekyear-week weekyear-week)
75+
(false? day-of-week?) (assoc :day-of-week day-of-week))})))))
6376

6477
(defn index-of [coll x]
6578
(first (keep-indexed #(when (= %2 x) %1) coll)))
@@ -97,3 +110,15 @@
97110
(update-in [:weeks] scale-fn)
98111
(update-in [:months] scale-fn)
99112
(update-in [:years] scale-fn))))
113+
114+
(defn get-week-year
115+
"Counterpart ot goog.date/getWeekNumber.
116+
month 0 is jan per goog.date"
117+
[year month date]
118+
(let [january (= month 0)
119+
december (= month 11)
120+
week-number (goog.date/getWeekNumber year month date)]
121+
(cond
122+
(and january (>= week-number 52)) (dec year)
123+
(and december (= week-number 1)) (inc year)
124+
:else year)))

src/cljs_time/internal/parse.cljs

+35-10
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,11 @@
101101
([lower upper]
102102
(fn [s] (parse-period s :days lower upper))))
103103

104+
(defn parse-day-of-week
105+
([limit] (parse-day 1 limit))
106+
([lower upper]
107+
(fn [s] (parse-period s :day-of-week lower upper))))
108+
104109
(defn parse-hours
105110
([limit] (parse-hours 1 limit))
106111
([lower upper]
@@ -254,6 +259,7 @@
254259
"E" (parse-day-name true)
255260
"EEE" (parse-day-name true)
256261
"EEEE" (parse-day-name false)
262+
"e" (parse-day-of-week 1 2)
257263
"a" (parse-meridiem)
258264
"A" (parse-meridiem)
259265
"Z" (parse-timezone :dddd)
@@ -285,20 +291,40 @@
285291
(throw (err))
286292
out)))))
287293

288-
(defn compile [class {:keys [default-year] :as fmt} values]
289-
(let [{:keys [years months days
290-
hours HOURS minutes seconds millis
291-
meridiem timezone]
292-
:as date-map} (->> values
293-
(remove (comp #{:quoted} first))
294-
(into {}))
295-
year (.getYear (Date.))
294+
(defn infer-years
295+
[years default-year]
296+
(let [year (.getYear (Date.))
296297
pivot (- year 30)
297298
century (- year (mod year 100))
298299
years (or years default-year 0)
299300
years (cond-> years
300301
(< years (mod (+ pivot 50) 100))
301-
(+ century))
302+
(+ century))]
303+
years))
304+
305+
(defn week-date->gregorian
306+
[{:keys [weekyear weekyear-week day-of-week] :as date-map}]
307+
(if (and weekyear weekyear-week)
308+
(let [date (Date. weekyear 0 4)]
309+
(.add date (Interval. 0 0 (* 7 (dec weekyear-week))))
310+
(.add date (Interval. 0 0 (- (or day-of-week 1)
311+
(inc (mod (dec (.getDay date)) 7)))))
312+
(-> date-map
313+
(assoc :years (.getYear date))
314+
(assoc :months (inc (.getMonth date)))
315+
(assoc :days (.getDate date))))
316+
date-map))
317+
318+
(defn compile [class fmt values]
319+
(let [{:keys [years months days
320+
hours HOURS minutes seconds millis
321+
meridiem timezone]
322+
:as date-map} (->> values
323+
(remove (comp #{:quoted} first))
324+
(into {})
325+
(i/valid-date?)
326+
(week-date->gregorian))
327+
years (infer-years years (:default-year fmt))
302328
months (when months (dec months))
303329
hours (if meridiem
304330
(if (#{:pm :PM} meridiem)
@@ -312,7 +338,6 @@
312338
timezone (if (instance? Interval timezone)
313339
timezone
314340
(Interval. Interval.SECONDS 0))]
315-
(i/valid-date? date-map)
316341
(doto (case class
317342
:goog.date.Date
318343
(Date. years months days)

src/cljs_time/internal/unparse.cljs

+18-10
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,16 @@
5050
(fn [s d]
5151
(unparse-period s d (.getDate d) min max))))
5252

53+
(defn unparse-day-of-week
54+
".getDay returns 0-6, shifts to 1-7"
55+
([min] (unparse-day-of-week min min))
56+
([min max]
57+
(fn [s d]
58+
(let [raw-day-of-week (.getDay d)
59+
day-of-week (if (= raw-day-of-week 0)
60+
7 raw-day-of-week)]
61+
(unparse-period s d day-of-week min max)))))
62+
5363
(defn unparse-day-of-year
5464
([min] (unparse-day min min))
5565
([min max]
@@ -88,16 +98,12 @@
8898
([min] (unparse-weekyear min min))
8999
([min max]
90100
(fn [s d]
91-
(let [year (.getYear d) month (.getMonth d) day (.getDate d)
92-
january (= month 0)
93-
december (= month 11)
94-
week-number (goog.date/getWeekNumber year month day)
95-
weekyear (cond (and january (>= week-number 52))
96-
(dec year)
97-
(and december (= week-number 1))
98-
(inc year)
99-
:else year)]
100-
(unparse-period s d weekyear min max)))))
101+
(let [year (.getYear d)
102+
month (.getMonth d)
103+
day (.getDate d)]
104+
(unparse-period s d
105+
(i/get-week-year year month day)
106+
min max)))))
101107

102108
(defn unparse-weekyear-week
103109
([min] (unparse-weekyear-week min min))
@@ -159,6 +165,7 @@
159165
"xxxx" [:weekyear 4 4]
160166
"w" [:weekyear-week 1 2]
161167
"ww" [:weekyear-week 2 2]
168+
"e" [:day-of-week 1 1]
162169
"E" [:day-name true]
163170
"EEE" [:day-name true]
164171
"EEEE" [:day-name false]
@@ -194,6 +201,7 @@
194201
:weekyear (apply unparse-weekyear args)
195202
:weekyear-week (apply unparse-weekyear-week args)
196203
:day-name (apply unparse-day-name args)
204+
:day-of-week (apply unparse-day-of-week args)
197205
:meridiem (apply unparse-meridiem args)
198206
:timezone (apply unparse-timezone args)
199207
:ordinal-suffix (let [[k] (syntax-list (dec i))]

test/cljs_time/core_test.cljs

+7-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
years? months? weeks? days? hours? minutes? seconds?
1919
extend start end mins-ago default-time-zone
2020
to-default-time-zone from-default-time-zone
21-
overlap week-number-of-year floor]]
21+
overlap week-number-of-year week-year floor]]
2222
[cljs-time.extend]))
2323

2424
(deftest test-now
@@ -550,6 +550,12 @@
550550
(is (= 1 (week-number-of-year (date-time 2012 12 31))))
551551
(is (= 1 (week-number-of-year (date-time 2013 1 1)))))
552552

553+
(deftest test-week-year
554+
(is (= 2015 (week-year (date-time 2014 12 29))))
555+
(is (= 2015 (week-year (date-time 2015 1 5))))
556+
(is (= 2009 (week-year (date-time 2010 1 3))))
557+
(is (= 2010 (week-year (date-time 2010 1 4)))))
558+
553559
(deftest test-number-of-days-in-the-month
554560
(is (= 31 (number-of-days-in-the-month 2012 1)))
555561
(is (= 31 (number-of-days-in-the-month (date-time 2012 1 3))))

test/cljs_time/format_test.cljs

+23-8
Original file line numberDiff line numberDiff line change
@@ -369,14 +369,29 @@
369369
(is (= "W02" (format/unparse fmt (time/date-time 2015 1 5))))
370370
(is (= "W01" (format/unparse fmt (time/date-time 2010 1 4))))
371371
(is (= "W01" (format/unparse fmt (time/date-time 2008 12 29)))))
372-
(comment
373-
;; no built in support for week-year in goog.date
374-
(let [fmt (format/formatters :weekyear-week)]
375-
(is (= "2015-W01" (format/unparse fmt (time/date-time 2014 12 29))))
376-
(is (= "2015-W02" (format/unparse fmt (time/date-time 2015 1 5))))
377-
(is (= "2009-W53" (format/unparse fmt (time/date-time 2010 1 3))))
378-
(is (= "2010-W01" (format/unparse fmt (time/date-time 2010 1 4))))
379-
(is (= "2009-W01" (format/unparse fmt (time/date-time 2008 12 29)))))))
372+
(let [fmt (format/formatters :weekyear-week)]
373+
(is (= "2015-W01" (format/unparse fmt (time/date-time 2014 12 29))))
374+
(is (= "2015-W02" (format/unparse fmt (time/date-time 2015 1 5))))
375+
(is (= "2009-W53" (format/unparse fmt (time/date-time 2010 1 3))))
376+
(is (= "2010-W01" (format/unparse fmt (time/date-time 2010 1 4))))
377+
(is (= "2009-W01" (format/unparse fmt (time/date-time 2008 12 29))))))
378+
379+
(deftest weekyear-week-day-test
380+
(let [fmt (format/formatters :weekyear-week-day)]
381+
(is (= "2015-W01-1"
382+
(format/unparse fmt (time/date-time 2014 12 29))))
383+
(is (= "2015-W01-2"
384+
(format/unparse fmt (time/date-time 2014 12 30))))
385+
(is (= "2015-W01-7"
386+
(format/unparse fmt (time/date-time 2015 1 4))))
387+
(is (= "2009-W53-7"
388+
(format/unparse fmt (time/date-time 2010 1 3))))
389+
(is (= (time/date-time 2014 12 29)
390+
(format/parse fmt "2015-W01-1")))
391+
(is (= (time/date-time 2014 12 30)
392+
(format/parse fmt "2015-W01-2")))
393+
(is (= (time/date-time 2015 1 4)
394+
(format/parse fmt "2015-W01-7")))))
380395

381396
(deftest parse-MM-test
382397
(is (= (date-time 2012 1 1)

0 commit comments

Comments
 (0)