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