ryoakg
6/23/2016 - 6:20 AM

java8 の java.time.* 関連

java8 の java.time.* 関連

;;; java.time.Local* -> java.sql.*
(java.sql.Date/valueOf (java.time.LocalDate/now)) ;; => #inst "2016-06-22T15:00:00.000-00:00"
(-> (java.time.Instant/now) .toEpochMilli java.sql.Date.);; => #inst "2016-06-23T13:25:55.577-00:00"

(java.sql.Time/valueOf (java.time.LocalTime/now)) ;; => #inst "1970-01-01T13:22:01.000-00:00"
(-> (java.time.Instant/now) .toEpochMilli java.sql.Time.) ;; => #inst "2016-06-23T13:25:40.615-00:00"

(java.sql.Timestamp/valueOf (java.time.LocalDateTime/now)) ;; => #inst "2016-06-23T13:22:05.241000000-00:00"
(-> (java.time.Instant/now) .toEpochMilli java.sql.Timestamp.) ;; => #inst "2016-06-23T13:24:59.904000000-00:00"


;;; java.sql.* -> java.time.Local*
(let [ts (java.sql.Timestamp. 0)]
  [(.toLocalDateTime ts) (.toInstant ts)])
;; => [#object[java.time.LocalDateTime 0x7dcc3f36 "1970-01-01T09:00"] #object[java.time.Instant 0x3f9e981c "1970-01-01T00:00:00Z"]]

(let [t (java.sql.Time. 0)]
  [#_(.toInstant t)                     ;UnsupportedOperationException
   (.toLocalTime t)])
;; => [#object[java.time.LocalTime 0x7373a1e8 "09:00"]]

(let [d (java.sql.Date. 0)]
  [#_(.toInstant d)                       ;UnsupportedOperationException
   (.toLocalDate d)])
;; => [#object[java.time.LocalDate 0x23c74418 "1970-01-01"]]
;;; (java.time.LocalDate, java.time.LocalTime) => java.time.LocalDateTime
(let [d (java.time.LocalDate/now)
      t (java.time.LocalTime/now)]
  (java.time.LocalDateTime/of d t))
;; => #object[java.time.LocalDateTime 0x67edb530 "2016-10-08T08:51:37.782"]


;;; java.time.LocalDateTime => (java.time.LocalDate, java.time.LocalTime)
(let [dt (java.time.LocalDateTime/now)]
  [(.toLocalDate dt) (.toLocalTime dt)])
;; => [#object[java.time.LocalDate 0x6052ae93 "2016-10-08"] #object[java.time.LocalTime 0x24bec5b3 "08:51:39.718"]]
(require 'clojure.reflect)

(->> (clojure.reflect/reflect java.time.format.DateTimeFormatter)
     :members
     (filter #(= (:type %) 'java.time.format.DateTimeFormatter))
     (map :name))
(comment
  (ISO_LOCAL_TIME
   ISO_ORDINAL_DATE
   ISO_OFFSET_DATE
   ISO_TIME
   ISO_LOCAL_DATE_TIME
   ISO_INSTANT
   RFC_1123_DATE_TIME
   ISO_DATE
   ISO_WEEK_DATE
   ISO_OFFSET_TIME
   ISO_LOCAL_DATE
   ISO_ZONED_DATE_TIME
   ISO_OFFSET_DATE_TIME
   ISO_DATE_TIME
   BASIC_ISO_DATE      ))


(import 'java.time.format.DateTimeFormatter)

(def ^:private t (java.time.ZonedDateTime/now))
(.format t DateTimeFormatter/ISO_LOCAL_TIME      ) ; => "20:42:31.072"
(.format t DateTimeFormatter/ISO_ORDINAL_DATE    ) ; => "2016-246+09:00"
(.format t DateTimeFormatter/ISO_OFFSET_DATE     ) ; => "2016-09-02+09:00"
(.format t DateTimeFormatter/ISO_TIME            ) ; => "20:42:31.072+09:00"
(.format t DateTimeFormatter/ISO_LOCAL_DATE_TIME ) ; => "2016-09-02T20:42:31.072"
(.format t DateTimeFormatter/ISO_INSTANT         ) ; => "2016-09-02T11:42:31.072Z"
(.format t DateTimeFormatter/RFC_1123_DATE_TIME  ) ; => "Fri, 2 Sep 2016 20:42:31 +0900"
(.format t DateTimeFormatter/ISO_DATE            ) ; => "2016-09-02+09:00"
(.format t DateTimeFormatter/ISO_WEEK_DATE       ) ; => "2016-W35-5+09:00"
(.format t DateTimeFormatter/ISO_OFFSET_TIME     ) ; => "20:42:31.072+09:00"
(.format t DateTimeFormatter/ISO_LOCAL_DATE      ) ; => "2016-09-02"
(.format t DateTimeFormatter/ISO_ZONED_DATE_TIME ) ; => "2016-09-02T20:42:31.072+09:00[Asia/Tokyo]"
(.format t DateTimeFormatter/ISO_OFFSET_DATE_TIME) ; => "2016-09-02T20:42:31.072+09:00"
(.format t DateTimeFormatter/ISO_DATE_TIME       ) ; => "2016-09-02T20:42:31.072+09:00[Asia/Tokyo]"
(.format t DateTimeFormatter/BASIC_ISO_DATE      ) ; => "20160902+0900"

(.format (java.time.LocalDate/now) java.time.format.DateTimeFormatter/BASIC_ISO_DATE      ) ; => "20160827"
(set-env! :dependencies '[[org.clojure/tools.macro "0.1.2"]])
(require '[clojure.tools.macro :refer :all])

;;; http://qiita.com/tag1216/items/91a471b33f383981bfaa
;;; http://qiita.com/tag1216/items/9cb33a39a6666983491d

(def classes
  [java.time.LocalDate
   java.time.LocalTime
   java.time.LocalDateTime
   java.time.chrono.JapaneseDate
   java.time.OffsetDateTime
   java.time.ZonedDateTime
   java.time.Instant])

;;; current time
(macrolet [(map-now [xs]
                    (mapv (fn [x] `(. ~(if (symbol? x) (resolve x) x)
                                      now))
                          (if (symbol? xs) (var-get (resolve xs)) xs)))]
  (map-now classes))


;;; accessors
(macrolet [(map-bean [xs]
                     (mapv (fn [x] `(bean (. ~(if (symbol? x) (resolve x) x)
                                             now)))
                           (if (symbol? xs) (var-get (resolve xs)) xs)))]
  (map-bean classes))


;;; make specific time
(bean (java.time.LocalTime/of 1 2 3))
;; => {:class java.time.LocalTime, :hour 1, :minute 2, :nano 0, :second 3}


;;; truncate
(bean (.truncatedTo (java.time.LocalTime/now) java.time.temporal.ChronoUnit/SECONDS))
;; => {:class java.time.LocalTime, :hour 14, :minute 49, :nano 0, :second 11}
(bean (.truncatedTo (java.time.LocalTime/now) java.time.temporal.ChronoUnit/MINUTES))
;; => {:class java.time.LocalTime, :hour 14, :minute 48, :nano 0, :second 0}
(bean (.truncatedTo (java.time.LocalTime/now) java.time.temporal.ChronoUnit/HOURS))
;; => {:class java.time.LocalTime, :hour 14, :minute 0, :nano 0, :second 0}


;;; modification
(-> (java.time.LocalTime/of 1 2 3)
    (.minusHours 1)
    (.plusMinutes 10)
    (.plusSeconds 30)
    (.plusNanos 50)
    bean)
;; => {:class java.time.LocalTime, :hour 0, :minute 12, :nano 50, :second 33}


;;; type conversion

;; with java.util.Date
(let [instant (.toInstant (java.util.Date.))
      zone    (java.time.ZoneId/systemDefault)]
  (java.time.LocalDateTime/ofInstant instant zone)
  [
   ;; (java.time.LocalDate/ofInstant instant zone); No matching method
   ;; (java.time.LocalTime/ofInstant instant zone); No matching method
   (java.time.LocalDateTime/ofInstant instant zone)
   ;; (java.time.chrono.JapaneseDate/ofInstant instant zone) ; No matching method
   (java.time.OffsetDateTime/ofInstant instant zone)
   (java.time.ZonedDateTime/ofInstant instant zone)])

;; java.time.*
(let [t (java.time.LocalDateTime/now)]
  [(.atZone    t (java.time.ZoneId/systemDefault))
   (.atOffset  t (java.time.ZoneOffset/ofHours 9))
   (.toInstant t java.time.ZoneOffset/UTC)])
;; [#object[java.time.ZonedDateTime 0x5aee0f99 "2016-06-23T15:01:33.378+09:00[Asia/Tokyo]"]
;;  #object[java.time.OffsetDateTime 0x363f2e36 "2016-06-23T15:01:33.378+09:00"]
;;  #object[java.time.Instant 0x102138e6 "2016-06-23T15:01:33.378Z"]]


;;; formatting
;;; https://docs.oracle.com/javase/jp/8/docs/api/java/time/format/DateTimeFormatter.html#predefined
(let [f (java.time.format.DateTimeFormatter/ofPattern "yyyy/MM/dd HH:mm:ss")
      t (java.time.LocalDateTime/parse "2015/12/15 23:30:59" f)]
  [t (.format t f)])
;; => [#object[java.time.LocalDateTime 0xcc237ff "2015-12-15T23:30:59"] "2015/12/15 23:30:59"]

(let [d (java.time.LocalDate/of 2015 5 1)
      f (.. (java.time.format.DateTimeFormatterBuilder.)
            (appendPattern "yyyy/MM/dd(E) ")
            (appendLiteral "第")
            (appendValue (.weekOfMonth (java.time.temporal.WeekFields/of java.time.DayOfWeek/MONDAY 1)))
            (appendLiteral "週")
            toFormatter)]
  (->> (range 10)
       (map #(.format (.plusDays d %) f))))
;; ("2015/05/01(金) 第1週"
;;  "2015/05/02(土) 第1週"
;;  "2015/05/03(日) 第1週"
;;  "2015/05/04(月) 第2週"
;;  "2015/05/05(火) 第2週"
;;  "2015/05/06(水) 第2週"
;;  "2015/05/07(木) 第2週"
;;  "2015/05/08(金) 第2週"
;;  "2015/05/09(土) 第2週"
;;  "2015/05/10(日) 第2週")

(let [d (java.time.LocalDate/of 2015 5 1)
      f (.. (java.time.format.DateTimeFormatterBuilder.)
            (appendPattern "yyyy/MM/dd(E) ")
            (appendLiteral "第")
            (appendValue (.weekOfMonth (java.time.temporal.WeekFields/of java.time.DayOfWeek/MONDAY 7)))
            (appendLiteral "週")
            toFormatter)]
  (->> (range 10)
       (map #(.format (.plusDays d %) f))))
;; ("2015/05/01(金) 第0週"
;;  "2015/05/02(土) 第0週"
;;  "2015/05/03(日) 第0週"
;;  "2015/05/04(月) 第1週"
;;  "2015/05/05(火) 第1週"
;;  "2015/05/06(水) 第1週"
;;  "2015/05/07(木) 第1週"
;;  "2015/05/08(金) 第1週"
;;  "2015/05/09(土) 第1週"
;;  "2015/05/10(日) 第1週")




;;; time zone & offset
(= (java.time.ZoneId/getAvailableZoneIds)
   (java.time.ZoneOffset/getAvailableZoneIds)) ; => true

(java.time.ZoneId/systemDefault);; => #object[java.time.ZoneRegion 0x6b89dc2e "Asia/Tokyo"]
(java.time.ZoneId/of "Asia/Tokyo");; => #object[java.time.ZoneRegion 0x7249738f "Asia/Tokyo"]
(.normalized (java.time.ZoneId/of "Asia/Tokyo"));; => #object[java.time.ZoneRegion 0x3fcc7e48 "Asia/Tokyo"]
(.getId (java.time.ZoneId/of "Asia/Tokyo"));; => "Asia/Tokyo"
;; (java.time.ZoneId/from java.time.temporal.TemporalAccessor)
;; (java.time.ZoneId/from (java.time.chrono.JapaneseDate/now))


;; java.time.ZoneOffset
(java.time.ZoneOffset/of "Z");; => #object[java.time.ZoneOffset 0x2d7a4f03 "Z"]
(java.time.ZoneOffset/of "+1");; => #object[java.time.ZoneOffset 0x32edee77 "+01:00"]
(java.time.ZoneOffset/of "-1");; => #object[java.time.ZoneOffset 0x6bf36499 "-01:00"]
(java.time.ZoneOffset/of "+01:00");; => #object[java.time.ZoneOffset 0x32edee77 "+01:00"]
(java.time.ZoneOffset/of "-01:00") ;; => #object[java.time.ZoneOffset 0x6bf36499 "-01:00"]
(java.time.ZoneOffset/ofHours 3);; => #object[java.time.ZoneOffset 0x1269359a "+03:00"]
;; (java.time.ZoneOffset/of "foo") ;; => error

;;; constants
java.time.ZoneOffset/UTC ;;=> #object[java.time.ZoneOffset 0x2d7a4f03 "Z"]
java.time.ZoneOffset/MAX ;;=> #object[java.time.ZoneOffset 0x662ca71d "+18:00"]
java.time.ZoneOffset/MIN ;;=> #object[java.time.ZoneOffset 0xaf31fdf "-18:00"]

;;; alias
java.time.ZoneOffset/SHORT_IDS
;; => {"CTT" "Asia/Shanghai", "ART" "Africa/Cairo", "CNT" "America/St_Johns", "PRT" "America/Puerto_Rico", "PNT" "America/Phoenix", "PLT" "Asia/Karachi", "AST" "America/Anchorage", "BST" "Asia/Dhaka", "CST" "America/Chicago", "EST" "-05:00", "HST" "-10:00", "JST" "Asia/Tokyo", "IST" "Asia/Kolkata", "AGT" "America/Argentina/Buenos_Aires", "NST" "Pacific/Auckland", "MST" "-07:00", "AET" "Australia/Sydney", "BET" "America/Sao_Paulo", "PST" "America/Los_Angeles", "ACT" "Australia/Darwin", "SST" "Pacific/Guadalcanal", "VST" "Asia/Ho_Chi_Minh", "CAT" "Africa/Harare", "ECT" "Europe/Paris", "EAT" "Africa/Addis_Ababa", "IET" "America/Indiana/Indianapolis", "MIT" "Pacific/Apia", "NET" "Asia/Yerevan"}



;;; http://d.hatena.ne.jp/nowokay/20130917
(.. (java.time.ZoneId/of "Asia/Tokyo") getRules isFixedOffset) ;; => false
(.. (java.time.ZoneId/of "UTC") getRules isFixedOffset) ;; => true

(->> (java.time.ZoneId/of "Asia/Tokyo")
     .getRules
     .getTransitions
     (map str))
;; ("Transition[Overlap at 1888-01-01T00:18:59+09:18:59 to +09:00]"
;;  "Transition[Gap at 1948-05-02T02:00+09:00 to +10:00]"
;;  "Transition[Overlap at 1948-09-11T02:00+10:00 to +09:00]"
;;  "Transition[Gap at 1949-04-03T02:00+09:00 to +10:00]"
;;  "Transition[Overlap at 1949-09-10T02:00+10:00 to +09:00]"
;;  "Transition[Gap at 1950-05-07T02:00+09:00 to +10:00]"
;;  "Transition[Overlap at 1950-09-09T02:00+10:00 to +09:00]"
;;  "Transition[Gap at 1951-05-06T02:00+09:00 to +10:00]"
;;  "Transition[Overlap at 1951-09-08T02:00+10:00 to +09:00]")
(let [now   (java.time.LocalDate/now)
      now-1 (.minusDays now 1)]
  [(.isAfter  now now-1)
   (.isBefore now now-1)
   (.isEqual  now now-1)])
;; => [true false false]