github.com/gogf/gf/v2@v2.7.4/os/gtime/gtime_format.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/gogf/gf. 6 7 package gtime 8 9 import ( 10 "bytes" 11 "regexp" 12 "strconv" 13 "strings" 14 15 "github.com/gogf/gf/v2/text/gregex" 16 ) 17 18 var ( 19 // Refer: http://php.net/manual/en/function.date.php 20 formats = map[byte]string{ 21 'd': "02", // Day: Day of the month, 2 digits with leading zeros. Eg: 01 to 31. 22 'D': "Mon", // Day: A textual representation of a day, three letters. Eg: Mon through Sun. 23 'w': "Monday", // Day: Numeric representation of the day of the week. Eg: 0 (for Sunday) through 6 (for Saturday). 24 'N': "Monday", // Day: ISO-8601 numeric representation of the day of the week. Eg: 1 (for Monday) through 7 (for Sunday). 25 'j': "=j=02", // Day: Day of the month without leading zeros. Eg: 1 to 31. 26 'S': "02", // Day: English ordinal suffix for the day of the month, 2 characters. Eg: st, nd, rd or th. Works well with j. 27 'l': "Monday", // Day: A full textual representation of the day of the week. Eg: Sunday through Saturday. 28 'z': "", // Day: The day of the year (starting from 0). Eg: 0 through 365. 29 'W': "", // Week: ISO-8601 week number of year, weeks starting on Monday. Eg: 42 (the 42nd week in the year). 30 'F': "January", // Month: A full textual representation of a month, such as January or March. Eg: January through December. 31 'm': "01", // Month: Numeric representation of a month, with leading zeros. Eg: 01 through 12. 32 'M': "Jan", // Month: A short textual representation of a month, three letters. Eg: Jan through Dec. 33 'n': "1", // Month: Numeric representation of a month, without leading zeros. Eg: 1 through 12. 34 't': "", // Month: Number of days in the given month. Eg: 28 through 31. 35 'Y': "2006", // Year: A full numeric representation of a year, 4 digits. Eg: 1999 or 2003. 36 'y': "06", // Year: A two-digit representation of a year. Eg: 99 or 03. 37 'a': "pm", // Time: Lowercase Ante meridiem and Post meridiem. Eg: am or pm. 38 'A': "PM", // Time: Uppercase Ante meridiem and Post meridiem. Eg: AM or PM. 39 'g': "3", // Time: 12-hour format of an hour without leading zeros. Eg: 1 through 12. 40 'G': "=G=15", // Time: 24-hour format of an hour without leading zeros. Eg: 0 through 23. 41 'h': "03", // Time: 12-hour format of an hour with leading zeros. Eg: 01 through 12. 42 'H': "15", // Time: 24-hour format of an hour with leading zeros. Eg: 00 through 23. 43 'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59. 44 's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59. 45 'u': "=u=.000", // Time: Milliseconds. Eg: 234, 678. 46 'U': "", // Time: Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT). 47 'O': "-0700", // Zone: Difference to Greenwich time (GMT) in hours. Eg: +0200. 48 'P': "-07:00", // Zone: Difference to Greenwich time (GMT) with colon between hours and minutes. Eg: +02:00. 49 'T': "MST", // Zone: Timezone abbreviation. Eg: UTC, EST, MDT ... 50 'c': "2006-01-02T15:04:05-07:00", // Format: ISO 8601 date. Eg: 2004-02-12T15:19:21+00:00. 51 'r': "Mon, 02 Jan 06 15:04 MST", // Format: RFC 2822 formatted date. Eg: Thu, 21 Dec 2000 16:01:07 +0200. 52 } 53 54 // Week to number mapping. 55 weekMap = map[string]string{ 56 "Sunday": "0", 57 "Monday": "1", 58 "Tuesday": "2", 59 "Wednesday": "3", 60 "Thursday": "4", 61 "Friday": "5", 62 "Saturday": "6", 63 } 64 65 // Day count of each month which is not in leap year. 66 dayOfMonth = []int{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334} 67 ) 68 69 // Format formats and returns the formatted result with custom `format`. 70 // Refer method Layout, if you want to follow stdlib layout. 71 func (t *Time) Format(format string) string { 72 if t == nil { 73 return "" 74 } 75 runes := []rune(format) 76 buffer := bytes.NewBuffer(nil) 77 for i := 0; i < len(runes); { 78 switch runes[i] { 79 case '\\': 80 if i < len(runes)-1 { 81 buffer.WriteRune(runes[i+1]) 82 i += 2 83 continue 84 } else { 85 return buffer.String() 86 } 87 case 'W': 88 buffer.WriteString(strconv.Itoa(t.WeeksOfYear())) 89 case 'z': 90 buffer.WriteString(strconv.Itoa(t.DayOfYear())) 91 case 't': 92 buffer.WriteString(strconv.Itoa(t.DaysInMonth())) 93 case 'U': 94 buffer.WriteString(strconv.FormatInt(t.Unix(), 10)) 95 default: 96 if runes[i] > 255 { 97 buffer.WriteRune(runes[i]) 98 break 99 } 100 if f, ok := formats[byte(runes[i])]; ok { 101 result := t.Time.Format(f) 102 // Particular chars should be handled here. 103 switch runes[i] { 104 case 'j': 105 for _, s := range []string{"=j=0", "=j="} { 106 result = strings.ReplaceAll(result, s, "") 107 } 108 buffer.WriteString(result) 109 case 'G': 110 for _, s := range []string{"=G=0", "=G="} { 111 result = strings.ReplaceAll(result, s, "") 112 } 113 buffer.WriteString(result) 114 case 'u': 115 buffer.WriteString(strings.ReplaceAll(result, "=u=.", "")) 116 case 'w': 117 buffer.WriteString(weekMap[result]) 118 case 'N': 119 buffer.WriteString(strings.ReplaceAll(weekMap[result], "0", "7")) 120 case 'S': 121 buffer.WriteString(formatMonthDaySuffixMap(result)) 122 default: 123 buffer.WriteString(result) 124 } 125 } else { 126 buffer.WriteRune(runes[i]) 127 } 128 } 129 i++ 130 } 131 return buffer.String() 132 } 133 134 // FormatNew formats and returns a new Time object with given custom `format`. 135 func (t *Time) FormatNew(format string) *Time { 136 if t == nil { 137 return nil 138 } 139 return NewFromStr(t.Format(format)) 140 } 141 142 // FormatTo formats `t` with given custom `format`. 143 func (t *Time) FormatTo(format string) *Time { 144 if t == nil { 145 return nil 146 } 147 t.Time = NewFromStr(t.Format(format)).Time 148 return t 149 } 150 151 // Layout formats the time with stdlib layout and returns the formatted result. 152 func (t *Time) Layout(layout string) string { 153 if t == nil { 154 return "" 155 } 156 return t.Time.Format(layout) 157 } 158 159 // LayoutNew formats the time with stdlib layout and returns the new Time object. 160 func (t *Time) LayoutNew(layout string) *Time { 161 if t == nil { 162 return nil 163 } 164 newTime, err := StrToTimeLayout(t.Layout(layout), layout) 165 if err != nil { 166 panic(err) 167 } 168 return newTime 169 } 170 171 // LayoutTo formats `t` with stdlib layout. 172 func (t *Time) LayoutTo(layout string) *Time { 173 if t == nil { 174 return nil 175 } 176 newTime, err := StrToTimeLayout(t.Layout(layout), layout) 177 if err != nil { 178 panic(err) 179 } 180 t.Time = newTime.Time 181 return t 182 } 183 184 // IsLeapYear checks whether the time is leap year. 185 func (t *Time) IsLeapYear() bool { 186 year := t.Year() 187 if (year%4 == 0 && year%100 != 0) || year%400 == 0 { 188 return true 189 } 190 return false 191 } 192 193 // DayOfYear checks and returns the position of the day for the year. 194 func (t *Time) DayOfYear() int { 195 var ( 196 day = t.Day() 197 month = t.Month() 198 ) 199 if t.IsLeapYear() { 200 if month > 2 { 201 return dayOfMonth[month-1] + day 202 } 203 return dayOfMonth[month-1] + day - 1 204 } 205 return dayOfMonth[month-1] + day - 1 206 } 207 208 // DaysInMonth returns the day count of current month. 209 func (t *Time) DaysInMonth() int { 210 switch t.Month() { 211 case 1, 3, 5, 7, 8, 10, 12: 212 return 31 213 case 4, 6, 9, 11: 214 return 30 215 } 216 if t.IsLeapYear() { 217 return 29 218 } 219 return 28 220 } 221 222 // WeeksOfYear returns the point of current week for the year. 223 func (t *Time) WeeksOfYear() int { 224 _, week := t.ISOWeek() 225 return week 226 } 227 228 // formatToStdLayout converts custom format to stdlib layout. 229 func formatToStdLayout(format string) string { 230 b := bytes.NewBuffer(nil) 231 for i := 0; i < len(format); { 232 switch format[i] { 233 case '\\': 234 if i < len(format)-1 { 235 b.WriteByte(format[i+1]) 236 i += 2 237 continue 238 } else { 239 return b.String() 240 } 241 242 default: 243 if f, ok := formats[format[i]]; ok { 244 // Handle particular chars. 245 switch format[i] { 246 case 'j': 247 b.WriteString("2") 248 case 'G': 249 b.WriteString("15") 250 case 'u': 251 if i > 0 && format[i-1] == '.' { 252 b.WriteString("000") 253 } else { 254 b.WriteString(".000") 255 } 256 257 default: 258 b.WriteString(f) 259 } 260 } else { 261 b.WriteByte(format[i]) 262 } 263 i++ 264 } 265 } 266 return b.String() 267 } 268 269 // formatToRegexPattern converts the custom format to its corresponding regular expression. 270 func formatToRegexPattern(format string) string { 271 s := regexp.QuoteMeta(formatToStdLayout(format)) 272 s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s) 273 s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s) 274 s, _ = gregex.ReplaceString(`\s+`, `\s+`, s) 275 return s 276 } 277 278 // formatMonthDaySuffixMap returns the short english word for current day. 279 func formatMonthDaySuffixMap(day string) string { 280 switch day { 281 case "01", "21", "31": 282 return "st" 283 case "02", "22": 284 return "nd" 285 case "03", "23": 286 return "rd" 287 default: 288 return "th" 289 } 290 }