timeutils.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package timeutils
  15. import (
  16. "fmt"
  17. "strings"
  18. "time"
  19. "yunion.io/x/pkg/errors"
  20. "yunion.io/x/pkg/util/regutils"
  21. )
  22. func UtcNow() time.Time {
  23. return time.Now().UTC()
  24. }
  25. func Utcify(now time.Time) time.Time {
  26. if now.IsZero() {
  27. val := time.Now().UTC()
  28. return val
  29. } else {
  30. return now.UTC()
  31. }
  32. }
  33. func Localify(now time.Time) time.Time {
  34. if now.IsZero() {
  35. return time.Now().Local()
  36. }
  37. return now.Local()
  38. }
  39. const (
  40. IsoTimeFormat = "2006-01-02T15:04:05Z07:00"
  41. IsoNoSecondTimeFormat = "2006-01-02T15:04Z07:00"
  42. FullIsoTimeFormat = "2006-01-02T15:04:05.000000Z07:00"
  43. FullIsoNanoTimeFormat = "2006-01-02T15:04:05.000000000Z07:00"
  44. MysqlTimeFormat = "2006-01-02 15:04:05"
  45. ClickhouseTimeFormat = "2006-01-02 15:04:05 +0000 UTC"
  46. NormalTimeFormat = "2006-01-02T15:04:05"
  47. FullNormalTimeFormat = "2006-01-02T15:04:05.000000"
  48. CompactTimeFormat = "20060102150405"
  49. DateFormat = "2006-01-02"
  50. ShortDateFormat = "20060102"
  51. DateExcelFormat = "01-02-06"
  52. MonthFormat = "2006-01"
  53. ShortMonthFormat = "200601"
  54. ZStackTimeFormat = "Jan 2, 2006 15:04:05 PM"
  55. IsoTimeFormat2 = "2006-01-02 15:04:05Z07:00"
  56. IsoNoSecondTimeFormat2 = "2006-01-02 15:04Z07:00"
  57. FullIsoNanoTimeFormat2 = "2006-01-02 15:04:05.000000000Z07:00"
  58. FullIsoNanoTimeFormat3 = "2006-01-02 15:04:05.000000000"
  59. RFC2882Format = time.RFC1123
  60. CephTimeFormat = "Mon Jan _2 15:04:05 2006"
  61. )
  62. func IsoTime(now time.Time) string {
  63. return Utcify(now).Format(IsoTimeFormat)
  64. }
  65. func IsoNoSecondTime(now time.Time) string {
  66. return Utcify(now).Format(IsoNoSecondTimeFormat)
  67. }
  68. func FullIsoTime(now time.Time) string {
  69. return Utcify(now).Format(FullIsoTimeFormat)
  70. }
  71. func FullIsoNanoTime(now time.Time) string {
  72. return Utcify(now).Format(FullIsoNanoTimeFormat)
  73. }
  74. func MysqlTime(now time.Time) string {
  75. return Utcify(now).Format(MysqlTimeFormat)
  76. }
  77. func ClickhouseTime(now time.Time) string {
  78. return Utcify(now).Format(ClickhouseTimeFormat)
  79. }
  80. func CompactTime(now time.Time) string {
  81. return Utcify(now).Format(CompactTimeFormat)
  82. }
  83. func RFC2882Time(now time.Time) string {
  84. return Utcify(now).Format(RFC2882Format)
  85. }
  86. func CephTime(now time.Time) string {
  87. return Utcify(now).Format(CephTimeFormat)
  88. }
  89. func DateStr(now time.Time) string {
  90. return Utcify(now).Format(DateFormat)
  91. }
  92. func ShortDate(now time.Time) string {
  93. return Utcify(now).Format(ShortDateFormat)
  94. }
  95. func DateExcelStr(now time.Time) string {
  96. return Utcify(now).Format(DateExcelFormat)
  97. }
  98. func MonthStr(now time.Time) string {
  99. return Utcify(now).Format(MonthFormat)
  100. }
  101. func ShortMonth(now time.Time) string {
  102. return Utcify(now).Format(ShortMonthFormat)
  103. }
  104. func ZStackTime(now time.Time) string {
  105. return Localify(now).Format(ZStackTimeFormat)
  106. }
  107. func ParseIsoTime(str string) (time.Time, error) {
  108. return time.Parse(IsoTimeFormat, str)
  109. }
  110. func ParseIsoTime2(str string) (time.Time, error) {
  111. return time.Parse(IsoTimeFormat2, str)
  112. }
  113. func ParseIsoNoSecondTime(str string) (time.Time, error) {
  114. return time.Parse(IsoNoSecondTimeFormat, str)
  115. }
  116. func ParseIsoNoSecondTime2(str string) (time.Time, error) {
  117. return time.Parse(IsoNoSecondTimeFormat2, str)
  118. }
  119. func toFullIsoNanoTimeFormat(str string) string {
  120. // 2019-09-17T20:50:17.66667134+08:00
  121. // 2019-11-19T18:54:48.084-08:00
  122. subsecStr := str[20:]
  123. pos := -1
  124. for _, s := range []byte{'Z', '+', '-'} {
  125. pos = strings.IndexByte(subsecStr, s)
  126. if pos >= 0 {
  127. break
  128. }
  129. }
  130. if pos < 0 { //避免-1越界
  131. pos = len(subsecStr)
  132. }
  133. leftOver := subsecStr[pos:]
  134. subsecStr = subsecStr[:pos]
  135. for len(subsecStr) < 9 {
  136. subsecStr += "0"
  137. }
  138. return str[:20] + subsecStr + leftOver
  139. }
  140. func ParseFullIsoTime(str string) (time.Time, error) {
  141. return time.Parse(FullIsoNanoTimeFormat, toFullIsoNanoTimeFormat(str))
  142. }
  143. func ParseFullIsoTime2(str string) (time.Time, error) {
  144. return time.Parse(FullIsoNanoTimeFormat2, toFullIsoNanoTimeFormat(str))
  145. }
  146. func ParseFullIsoTime3(str string) (time.Time, error) {
  147. return time.Parse(FullIsoNanoTimeFormat3, toFullIsoNanoTimeFormat(str))
  148. }
  149. func ParseMysqlTime(str string) (time.Time, error) {
  150. return time.Parse(MysqlTimeFormat, str)
  151. }
  152. func ParseClickhouseTime(str string) (time.Time, error) {
  153. return time.Parse(ClickhouseTimeFormat, str)
  154. }
  155. func ParseNormalTime(str string) (time.Time, error) {
  156. return time.Parse(NormalTimeFormat, str)
  157. }
  158. func ParseFullNormalTime(str string) (time.Time, error) {
  159. return time.Parse(FullNormalTimeFormat, str)
  160. }
  161. func ParseCompactTime(str string) (time.Time, error) {
  162. return time.Parse(CompactTimeFormat, str)
  163. }
  164. func ParseRFC2882Time(str string) (time.Time, error) {
  165. return time.Parse(RFC2882Format, str)
  166. }
  167. func ParseCephTime(str string) (time.Time, error) {
  168. return time.Parse(CephTimeFormat, str)
  169. }
  170. func ParseDate(str string) (time.Time, error) {
  171. return time.Parse(DateFormat, str)
  172. }
  173. func ParseShortDate(str string) (time.Time, error) {
  174. return time.Parse(ShortDateFormat, str)
  175. }
  176. func ParseDateExcel(str string) (time.Time, error) {
  177. return time.Parse(DateExcelFormat, str)
  178. }
  179. func ParseZStackDate(str string) (time.Time, error) {
  180. return time.ParseInLocation(ZStackTimeFormat, str, time.Local)
  181. }
  182. func ParseTimeStr(str string) (time.Time, error) {
  183. str = strings.TrimSpace(str)
  184. if regutils.MatchFullISOTime(str) {
  185. return ParseFullIsoTime(str)
  186. } else if regutils.MatchISOTime(str) {
  187. return ParseIsoTime(str)
  188. } else if regutils.MatchISONoSecondTime(str) {
  189. return ParseIsoNoSecondTime(str)
  190. } else if regutils.MatchFullISOTime2(str) {
  191. return ParseFullIsoTime2(str)
  192. } else if regutils.MatchFullISOTime3(str) {
  193. return ParseFullIsoTime3(str)
  194. } else if regutils.MatchISOTime2(str) {
  195. return ParseIsoTime2(str)
  196. } else if regutils.MatchISONoSecondTime2(str) {
  197. return ParseIsoNoSecondTime2(str)
  198. } else if regutils.MatchMySQLTime(str) {
  199. return ParseMysqlTime(str)
  200. } else if regutils.MatchClickhouseTime(str) {
  201. return ParseClickhouseTime(str)
  202. } else if regutils.MatchNormalTime(str) {
  203. return ParseNormalTime(str)
  204. } else if regutils.MatchFullNormalTime(str) {
  205. return ParseFullNormalTime(str)
  206. } else if regutils.MatchRFC2882Time(str) {
  207. return ParseRFC2882Time(str)
  208. } else if regutils.MatchCephTime(str) {
  209. return ParseCephTime(str)
  210. } else if regutils.MatchCompactTime(str) {
  211. return ParseCompactTime(str)
  212. } else if regutils.MatchDate(str) {
  213. return ParseDate(str)
  214. } else if regutils.MatchDateCompact(str) {
  215. return ParseShortDate(str)
  216. } else if regutils.MatchDateExcel(str) {
  217. return ParseDateExcel(str)
  218. } else if regutils.MatchZStackTime(str) {
  219. return ParseZStackDate(str)
  220. } else {
  221. return time.Time{}, fmt.Errorf("unknown time format %s", str)
  222. }
  223. }
  224. func ParseTimeStrInLocation(str string, loc *time.Location) (time.Time, error) {
  225. utcTm, err := ParseTimeStr(str)
  226. if err != nil {
  227. return utcTm, errors.Wrap(err, "ParseTimeStr")
  228. }
  229. if loc == nil {
  230. loc, _ = time.LoadLocation("Local")
  231. }
  232. _, offset := utcTm.In(loc).Zone()
  233. return utcTm.Add(-time.Duration(offset) * time.Second), nil
  234. }
  235. func ParseTimeStrInTimeZone(str string, tz string) (time.Time, error) {
  236. if len(tz) == 0 {
  237. tz = "Local"
  238. }
  239. loc, err := time.LoadLocation(tz)
  240. if err != nil {
  241. return time.Time{}, errors.Wrap(err, "LoadLocation")
  242. }
  243. return ParseTimeStrInLocation(str, loc)
  244. }
  245. func TimeZoneOffset(tz string) (int, error) {
  246. if len(tz) == 0 {
  247. tz = "Local"
  248. }
  249. loc, err := time.LoadLocation(tz)
  250. if err != nil {
  251. return 0, errors.Wrap(err, "LoadLocation")
  252. }
  253. _, offset := time.Now().In(loc).Zone()
  254. return offset, nil
  255. }