-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrtime.go
More file actions
458 lines (409 loc) · 11.2 KB
/
Copy pathrtime.go
File metadata and controls
458 lines (409 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
// Package rtime provides functionality for formatting dates in russian language with new placeholders.
//
// For example, this code formats date according to the actual GOST 2006 standart:
//
// t := rtime.Now()
// t.Format(rtime.GOST2016Word) // 1 марта 2023 г.
//
// List of the new placeholders: Январь, январь, Янв, янв, Января, января, Понедельник, понедельник, ПН, пн.
// Every placeholder existing in the original time package works as usual:
//
// t := rtime.RTime{time.Now()}
// t.Format("ПН/Mon, 2 Янв/Jan 2006") // "СР/Wed, 1 Мар/Mar 2023
package rtime
import (
"errors"
"fmt"
"time"
)
const (
Layout = time.Layout
ANSIC = time.ANSIC
UnixDate = time.UnixDate
RubyDate = time.RubyDate
RFC822 = time.RFC822
RFC822Z = time.RFC822Z
RFC850 = time.RFC850
RFC1123 = time.RFC1123
RFC1123Z = time.RFC1123Z
RFC3339 = time.RFC3339
RFC3339Nano = time.RFC3339Nano
Kitchen = time.Kitchen
Stamp = time.Stamp
StampMilli = time.StampMilli
StampMicro = time.StampMicro
StampNano = time.StampNano
DateTime = time.DateTime
DateOnly = time.DateOnly
TimeOnly = time.TimeOnly
)
// Additional
const (
GOST2016Numeric = "02.01.2006"
GOST2016Word = "2 января 2006 г."
GOST2003Word = "02 января 2006 г."
GOST2003NumericReverse = "2006.01.02"
)
const (
codeLongMonth = iota + 1 // Январь
codeLongMonthLower // январь
codeMonth // Янв
codeMonthLower // янв
codeLongMonthGenitive // Января
codeLongMonthGenitiveLower // января
codeLongWeekDay // Понедельник
codeLongWeekDayLower // понедельник
codeWeekDay // ПН
codeWeekDayLower // пн
)
var longMonthNames = []string{
"Январь",
"Февраль",
"Март",
"Апрель",
"Май",
"Июнь",
"Июль",
"Август",
"Сентябрь",
"Октябрь",
"Ноябрь",
"Декабрь",
}
var longMonthLowerNames = []string{
"январь",
"февраль",
"март",
"апрель",
"май",
"июнь",
"июль",
"август",
"сентябрь",
"октябрь",
"ноябрь",
"декабрь",
}
var monthNames = []string{
"Янв",
"Фев",
"Мар",
"Апр",
"Май",
"Июнь",
"Июль",
"Авг",
"Сен",
"Окт",
"Ноя",
"Дек",
}
var monthLowerNames = []string{
"янв",
"фев",
"мар",
"апр",
"май",
"июнь",
"июль",
"авг",
"сен",
"окт",
"ноя",
"дек",
}
var longMonthGenitiveNames = []string{
"Января",
"Февраля",
"Марта",
"Апреля",
"Мая",
"Июня",
"Июля",
"Августа",
"Сентября",
"Октября",
"Ноября",
"Декабря",
}
var longMonthGenitiveLowerNames = []string{
"января",
"февраля",
"марта",
"апреля",
"мая",
"июня",
"июля",
"августа",
"сентября",
"октября",
"ноября",
"декабря",
}
var longWeekDayNames = []string{
"Понедельник",
"Вторник",
"Среда",
"Четверг",
"Пятница",
"Суббота",
"Воскресенье",
}
var longWeekDayLowerNames = []string{
"понедельник",
"вторник",
"среда",
"четверг",
"пятница",
"суббота",
"воскресенье",
}
var weekDayNames = []string{
"ПН",
"ВТ",
"СР",
"ЧТ",
"ПТ",
"СБ",
"ВС",
}
var weekDayLowerNames = []string{
"пн",
"вт",
"ср",
"чт",
"пт",
"сб",
"вс",
}
var ErrInvalidNamesList = errors.New("invalid new names list")
// SetMonthNames set short month names (Янв, Фев, etc.)
func SetMonthNames(newNames []string) error {
if len(newNames) != len(monthNames) {
return ErrInvalidNamesList
}
monthNames = newNames
return nil
}
// SetMonthLowerNames set short month lower names (янв, фев, etc.)
func SetMonthLowerNames(newNames []string) error {
if len(newNames) != len(monthLowerNames) {
return ErrInvalidNamesList
}
monthLowerNames = newNames
return nil
}
// SetWeekDayNames set short week day names (ПН, ВТ, etc.)
func SetWeekDayNames(newNames []string) error {
if len(newNames) != len(weekDayNames) {
return ErrInvalidNamesList
}
weekDayNames = newNames
return nil
}
// SetWeekDayLowerNames set short week day lower names (пн, вт, etc.)
func SetWeekDayLowerNames(newNames []string) error {
if len(newNames) != len(weekDayLowerNames) {
return ErrInvalidNamesList
}
weekDayLowerNames = newNames
return nil
}
type month int
const (
January month = 1 + iota
February
March
April
May
June
July
August
September
October
November
December
)
func (m month) string(code int) string {
if January <= m && m <= December {
switch code {
case codeLongMonth:
return longMonthNames[m-1]
case codeLongMonthLower:
return longMonthLowerNames[m-1]
case codeMonth:
return monthNames[m-1]
case codeMonthLower:
return monthLowerNames[m-1]
case codeLongMonthGenitive:
return longMonthGenitiveNames[m-1]
case codeLongMonthGenitiveLower:
return longMonthGenitiveLowerNames[m-1]
default:
return fmt.Sprintf("Month(%d)", m)
}
}
return fmt.Sprintf("Month(%d)", m)
}
type day int
const (
Monday day = 1 + iota
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
)
func (d day) string(code int) string {
if Monday <= d && d <= Sunday {
switch code {
case codeWeekDay:
return weekDayNames[d-1]
case codeWeekDayLower:
return weekDayLowerNames[d-1]
case codeLongWeekDay:
return longWeekDayNames[d-1]
case codeLongWeekDayLower:
return longWeekDayLowerNames[d-1]
default:
return fmt.Sprintf("Day(%d)", d)
}
}
return fmt.Sprintf("Day(%d)", d)
}
// Now returns the current local time.
func Now() RTime {
return RTime{time.Now()}
}
// Date is the envelope for the time.Date function and creates RTime for the passed date params.
func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) RTime {
t := time.Date(year, month, day, hour, min, sec, nsec, loc)
return RTime{t}
}
// Unix is the envelope for the time.Unix function and creates RTime corresponding to the given Unix time,
// sec seconds and nsec nanoseconds since January 1, 1970 UTC.
func Unix(sec int64, nsec int64) RTime {
return RTime{time.Unix(sec, nsec)}
}
// UnixMilli is the envelope for the time.UnixMilli and returns the local Time corresponding to the given Unix time,
// msec milliseconds since January 1, 1970 UTC.
func UnixMilli(msec int64) RTime {
return RTime{time.UnixMilli(msec)}
}
// UnixMicro is the envelope for the time.UnixMicro and returns the local Time corresponding to the given Unix time,
// usec microseconds since January 1, 1970 UTC.
func UnixMicro(usec int64) RTime {
return RTime{time.UnixMicro(usec)}
}
type RTime struct {
time.Time
}
// Format returns a textual representation of the time value formatted according
// to the layout defined by the argument. See the documentation for the
// constant called Layout to see how to represent the layout format.
func (t RTime) Format(layout string) string {
var b []byte
maxLength := len(layout) + 10
b = make([]byte, 0, maxLength)
month := month(t.Month())
day := day(t.Weekday())
if day == 0 {
day = Sunday
}
rLayout := layout
for rLayout != "" {
prefix, std, suffix := nextChunk(layout)
if prefix != "" {
b = append(b, prefix...)
}
if std == 0 {
break
}
layout = suffix
switch std {
case codeLongMonth, codeLongMonthLower, codeMonth, codeMonthLower, codeLongMonthGenitive, codeLongMonthGenitiveLower:
m := month.string(std)
b = append(b, m...)
case codeWeekDay, codeWeekDayLower, codeLongWeekDay, codeLongWeekDayLower:
d := day.string(std)
b = append(b, d...)
}
}
layout = string(b)
return t.Time.Format(layout)
}
func nextChunk(layout string) (prefix string, std int, suffix string) {
rLayout := []rune(layout)
for i, r := range rLayout {
switch c := r; c {
case 'Я': // Январь, Янв, Января
if len(rLayout) >= i+3 && string(rLayout[i:i+3]) == "Янв" {
if len(rLayout) >= i+6 && string(rLayout[i:i+6]) == "Январь" {
return string(rLayout[0:i]), codeLongMonth, string(rLayout[i+6:])
}
if len(rLayout) >= i+6 && string(rLayout[i:i+6]) == "Января" {
return string(rLayout[0:i]), codeLongMonthGenitive, string(rLayout[i+6:])
}
return string(rLayout[0:i]), codeMonth, string(rLayout[i+3:])
}
case 'я': // январь, янв, января
if len(rLayout) >= i+3 && string(rLayout[i:i+3]) == "янв" {
if len(rLayout) >= i+6 && string(rLayout[i:i+6]) == "январь" {
return string(rLayout[0:i]), codeLongMonthLower, string(rLayout[i+6:])
}
if len(rLayout) >= i+6 && string(rLayout[i:i+6]) == "января" {
return string(rLayout[0:i]), codeLongMonthGenitiveLower, string(rLayout[i+6:])
}
return string(rLayout[0:i]), codeMonthLower, string(rLayout[i+3:])
}
case 'П': // Понедельник, ПН
if len(rLayout) >= i+2 && string(rLayout[i:i+2]) == "ПН" {
return string(rLayout[0:i]), codeWeekDay, string(rLayout[i+2:])
}
if len(rLayout) >= i+11 && string(rLayout[i:i+11]) == "Понедельник" {
return string(rLayout[0:i]), codeLongWeekDay, string(rLayout[i+11:])
}
case 'п': // понедельник, пн
if len(rLayout) >= i+2 && string(rLayout[i:i+2]) == "пн" {
return string(rLayout[0:i]), codeWeekDayLower, string(rLayout[i+2:])
}
if len(rLayout) >= i+11 && string(rLayout[i:i+11]) == "понедельник" {
return string(rLayout[0:i]), codeLongWeekDayLower, string(rLayout[i+11:])
}
}
}
return layout, 0, ""
}
// Add is the envelope for the Time.Add and returns the time t+d.
func (t RTime) Add(d time.Duration) RTime {
return RTime{t.Time.Add(d)}
}
// AddDate is the envelope for the Time.AddDate and returns the time corresponding to adding the
// given number of years, months, and days to t.
func (t RTime) AddDate(years int, months int, days int) RTime {
return RTime{t.Time.AddDate(years, months, days)}
}
// UTC is the envelope for the Time.UTC and returns t with the location set to UTC.
func (t RTime) UTC() RTime {
return RTime{t.Time.UTC()}
}
// Local is the envelope for the Time.Local and returns t with the location set to local time.
func (t RTime) Local() RTime {
return RTime{t.Time.Local()}
}
// In is the envelope for the Time.In returns a copy of t representing the same time instant, but
// with the copy's location information set to loc for display purposes.
func (t RTime) In(loc *time.Location) RTime {
return RTime{t.Time.In(loc)}
}
// Truncate is the envelope for the Time.Truncate
// and returns the result of rounding t down to a multiple of d (since the zero time).
func (t RTime) Truncate(d time.Duration) RTime {
return RTime{t.Time.Truncate(d)}
}
// Round is the envelope for the Time.Round
// and returns the result of rounding t to the nearest multiple of d (since the zero time).
func (t RTime) Round(d time.Duration) RTime {
return RTime{t.Time.Round(d)}
}