├── .github └── workflows │ └── pull_request.yml ├── .gitignore ├── LICENSE ├── README.md ├── carbon.go ├── carbonPeriod.go ├── carbonPeriod_test.go ├── carbon_test.go ├── carbonfreeze_test.go ├── carboninterval.go ├── carboninterval_test.go ├── diff_test.go ├── examples ├── addsub.go ├── comparison.go ├── diff.go ├── formats.go ├── instantiation.go ├── modifiers.go └── period.go ├── go.mod ├── go.sum ├── lang ├── af.json ├── ar.json ├── az.json ├── bg.json ├── bn.json ├── ca.json ├── cs.json ├── da.json ├── de.json ├── el.json ├── en.json ├── eo.json ├── es.json ├── et.json ├── eu.json ├── fa.json ├── fi.json ├── fo.json ├── fr.json ├── gl.json ├── he.json ├── hr.json ├── hu.json ├── hy.json ├── id.json ├── it.json ├── ja.json ├── ka.json ├── ko.json ├── loader.go ├── lt.json ├── lv.json ├── mk.json ├── ms.json ├── nl.json ├── no.json ├── pl.json ├── pt.json ├── pt_BR.json ├── ro.json ├── ru.json ├── sk.json ├── sl.json ├── sq.json ├── sr.json ├── sv.json ├── th.json ├── tr.json ├── uk.json ├── ur.json ├── uz.json ├── vi.json ├── zh.json └── zh_TW.json ├── translator.go └── translator_test.go /.github/workflows/pull_request.yml: -------------------------------------------------------------------------------- 1 | on: pull_request 2 | 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | go-version: [1.16, 1.17, 1.18] 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v2 13 | 14 | - name: Install Go 15 | uses: actions/setup-go@v2 16 | with: 17 | go-version: ${{ matrix.go-version }} 18 | 19 | - name: Install dependencies 20 | run: go get -t ./... 21 | 22 | - name: Test 23 | run: go test -coverprofile=coverage.txt -covermode=atomic 24 | 25 | - name: Upload coverage to codecov 26 | uses: codecov/codecov-action@v1 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | .idea/ 26 | *.iml 27 | 28 | vendor/ 29 | 30 | test.sh 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Carbon 2 | ====== 3 | [![Build Status](https://github.com/uniplaces/carbon/actions/workflows/pull_request.yml/badge.svg)](https://github.com/uniplaces/carbon/actions/workflows/pull_request.yml) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/uniplaces/carbon)](https://goreportcard.com/report/github.com/uniplaces/carbon) 5 | [![codecov](https://codecov.io/gh/uniplaces/carbon/branch/master/graph/badge.svg)](https://codecov.io/gh/uniplaces/carbon) 6 | [![GoDoc](https://godoc.org/github.com/uniplaces/carbon?status.svg)](https://godoc.org/github.com/uniplaces/carbon) 7 | [![License](http://img.shields.io/:license-apache-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) 8 | 9 | 10 | A simple extension for [Time](https://golang.org/pkg/time/#Time) based on PHP's [Carbon](http://carbon.nesbot.com) library. 11 | 12 | __Features:__ 13 | 14 | * [Time](https://golang.org/pkg/time/#Time) is embedded into Carbon (provides access to all of [Time](https://golang.org/pkg/time/#Time)'s functionality) 15 | * Supports addition and subtraction of dates 16 | * Provides methods to compare dates 17 | * Supports date formatting in common formats 18 | * Easily calculate difference between dates 19 | * Ease testing with dates by using `carbon.Freeze()` and `carbon.Now()` 20 | 21 | __To do:__ 22 | 23 | * Implement all localization features as in Carbon 24 | * Improve the code style to be more idiomatic Go 25 | 26 | ## Getting started 27 | Install Carbon: 28 | ``` 29 | go get github.com/uniplaces/carbon 30 | ``` 31 | 32 | Add to your imports to start using Carbon 33 | ```go 34 | import "github.com/uniplaces/carbon" 35 | ``` 36 | 37 | ## Examples 38 | A simple example to get you started: 39 | ```go 40 | package main 41 | 42 | import ( 43 | "fmt" 44 | "time" 45 | 46 | "github.com/uniplaces/carbon" 47 | ) 48 | 49 | func main() { 50 | fmt.Printf("Right now is %s\n", carbon.Now().DateTimeString()) 51 | 52 | today, _ := carbon.NowInLocation("America/Vancouver") 53 | fmt.Printf("Right now in Vancouver is %s\n", today) 54 | 55 | fmt.Printf("Tomorrow is %s\n", carbon.Now().AddDay()) 56 | fmt.Printf("Last week is %s\n", carbon.Now().SubWeek()) 57 | 58 | nextOlympics, _ := carbon.CreateFromDate(2016, time.August, 5, "Europe/London") 59 | nextOlympics = nextOlympics.AddYears(4) 60 | fmt.Printf("Next olympics are in %d\n", nextOlympics.Year()) 61 | 62 | if carbon.Now().IsWeekend() { 63 | fmt.Printf("Party time!") 64 | } 65 | } 66 | ``` 67 | 68 | You can also check the `examples/` folder for more examples. 69 | 70 | ## Contributing 71 | Please feel free to make suggestions, create issues, fork the repository and send pull requests! 72 | 73 | ## Licence 74 | Copyright 2016 UNIPLACES 75 | 76 | Licensed under the Apache License, Version 2.0 (the "License"); 77 | you may not use this file except in compliance with the License. 78 | You may obtain a copy of the License at 79 | 80 | http://www.apache.org/licenses/LICENSE-2.0 81 | 82 | Unless required by applicable law or agreed to in writing, software 83 | distributed under the License is distributed on an "AS IS" BASIS, 84 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 85 | See the License for the specific language governing permissions and 86 | limitations under the License. 87 | -------------------------------------------------------------------------------- /carbon.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 UNIPLACES 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 | 15 | // Package `carbon` is an extension to Go's time library based on PHP's Carbon library 16 | package carbon 17 | 18 | import ( 19 | "errors" 20 | "math" 21 | "strings" 22 | "time" 23 | ) 24 | 25 | // Represents the number of elements in a given period 26 | const ( 27 | secondsPerMinute = 60 28 | minutesPerHour = 60 29 | hoursPerDay = 24 30 | daysPerWeek = 7 31 | monthsPerQuarter = 3 32 | monthsPerYear = 12 33 | yearsPerCenturies = 100 34 | yearsPerDecade = 10 35 | weeksPerLongYear = 53 36 | daysInLeapYear = 366 37 | daysInNormalYear = 365 38 | secondsInWeek = 691200 39 | ) 40 | 41 | // Represents the different string formats for dates 42 | const ( 43 | DefaultFormat = "2006-01-02 15:04:05" 44 | DateFormat = "2006-01-02" 45 | FormattedDateFormat = "Jan 2, 2006" 46 | TimeFormat = "15:04:05" 47 | HourMinuteFormat = "15:04" 48 | HourFormat = "15" 49 | DayDateTimeFormat = "Mon, Jan 2, 2006 3:04 PM" 50 | CookieFormat = "Monday, 02-Jan-2006 15:04:05 MST" 51 | RFC822Format = "Mon, 02 Jan 06 15:04:05 -0700" 52 | RFC1036Format = "Mon, 02 Jan 06 15:04:05 -0700" 53 | RFC2822Format = "Mon, 02 Jan 2006 15:04:05 -0700" 54 | RFC3339Format = "2006-01-02T15:04:05-07:00" 55 | RSSFormat = "Mon, 02 Jan 2006 15:04:05 -0700" 56 | ) 57 | 58 | // The Carbon type represents a Time instance. 59 | // Provides a simple API extension for Time. 60 | type Carbon struct { 61 | time.Time 62 | weekStartsAt time.Weekday 63 | weekEndsAt time.Weekday 64 | weekendDays []time.Weekday 65 | stringFormat string 66 | Translator *Translator 67 | } 68 | 69 | // Used for testing purposes 70 | var ( 71 | isTimeFrozen bool 72 | currentFrozenTime time.Time 73 | ) 74 | 75 | // NewCarbon returns a pointer to a new Carbon instance 76 | func NewCarbon(t time.Time) *Carbon { 77 | wds := []time.Weekday{ 78 | time.Saturday, 79 | time.Sunday, 80 | } 81 | return &Carbon{ 82 | Time: t, 83 | weekStartsAt: time.Monday, 84 | weekEndsAt: time.Sunday, 85 | weekendDays: wds, 86 | stringFormat: DefaultFormat, 87 | Translator: translator(), 88 | } 89 | } 90 | 91 | // Freeze allows time to be frozen to facilitate testing 92 | func Freeze(time time.Time) { 93 | currentFrozenTime = time 94 | isTimeFrozen = true 95 | } 96 | 97 | // UnFreeze returns time to normal operation 98 | func UnFreeze() { 99 | isTimeFrozen = false 100 | } 101 | 102 | // IsTimeFrozen allows checking if time has been frozen 103 | func IsTimeFrozen() bool { 104 | return isTimeFrozen 105 | } 106 | 107 | // After will be behave like time.After unless time has been frozen 108 | // If time is frozen it will add the expected delay and immediately send the frozen time on the returned channel 109 | func After(d time.Duration) <-chan time.Time { 110 | if isTimeFrozen { 111 | currentFrozenTime = currentFrozenTime.Add(d) 112 | c := make(chan time.Time, 1) 113 | c <- currentFrozenTime 114 | return c 115 | } 116 | 117 | return time.After(d) 118 | } 119 | 120 | // Tick will be behave like time.Tick unless time has been frozen 121 | // If time is frozen it will tick normally but the date will be based on the frozen date 122 | func Tick(d time.Duration) <-chan time.Time { 123 | if isTimeFrozen { 124 | c := make(chan time.Time, 1) 125 | go func() { 126 | for { 127 | currentFrozenTime = currentFrozenTime.Add(d) 128 | c <- currentFrozenTime 129 | } 130 | }() 131 | return c 132 | } 133 | 134 | return time.Tick(d) 135 | } 136 | 137 | // Sleep will be behave like time.Sleep unless time has been frozen 138 | // If time is frozen it will add the expected sleep delay and return immediately 139 | func Sleep(d time.Duration) { 140 | if isTimeFrozen && d > 0 { 141 | currentFrozenTime = currentFrozenTime.Add(d) 142 | 143 | return 144 | } 145 | 146 | time.Sleep(d) 147 | } 148 | 149 | // create returns a new carbon pointe. It is a helper function to create new dates 150 | func create(y int, mon time.Month, d, h, m, s, ns int, l *time.Location) *Carbon { 151 | return NewCarbon(time.Date(y, mon, d, h, m, s, ns, l)) 152 | } 153 | 154 | // Create returns a new pointer to Carbon instance from a specific date and time. 155 | // If the location is invalid, it returns an error instead. 156 | func Create(y int, mon time.Month, d, h, m, s, ns int, location string) (*Carbon, error) { 157 | l, err := time.LoadLocation(location) 158 | if err != nil { 159 | return nil, err 160 | } 161 | return create(y, mon, d, h, m, s, ns, l), nil 162 | } 163 | 164 | // CreateFromDate returns a new pointer to a Carbon instance from just a date. 165 | // The time portion is set to now. 166 | // If the location is invalid, it returns an error instead. 167 | func CreateFromDate(y int, mon time.Month, d int, location string) (*Carbon, error) { 168 | h, m, s := Now().Clock() 169 | ns := Now().Nanosecond() 170 | 171 | return Create(y, mon, d, h, m, s, ns, location) 172 | } 173 | 174 | // CreateFromTime returns a new pointer to a Carbon instance from just a date. 175 | // The time portion is set to now. 176 | // If the locations is invalid, it returns an error instead. 177 | func CreateFromTime(h, m, s, ns int, location string) (*Carbon, error) { 178 | y, mon, d := Now().Date() 179 | 180 | return Create(y, mon, d, h, m, s, ns, location) 181 | } 182 | 183 | // CreateFromFormat returns a new pointer to a Carbon instance from a specific format. 184 | // If the location is invalid, it returns an error instead. 185 | func CreateFromFormat(layout, value string, location string) (*Carbon, error) { 186 | l, err := time.LoadLocation(location) 187 | if err != nil { 188 | return nil, err 189 | } 190 | t, err := time.ParseInLocation(layout, value, l) 191 | if err != nil { 192 | return nil, err 193 | } 194 | 195 | return NewCarbon(t), nil 196 | } 197 | 198 | // CreateFromTimestamp returns a new pointer to a Carbon instance from a timestamp. 199 | // If the location is invalid, it returns an error instead. 200 | func CreateFromTimestamp(timestamp int64, location string) (*Carbon, error) { 201 | l, err := time.LoadLocation(location) 202 | if err != nil { 203 | return nil, err 204 | } 205 | t := NewCarbon(Now().In(l)) 206 | t.SetTimestamp(timestamp) 207 | 208 | return t, nil 209 | } 210 | 211 | // CreateFromTimestampUTC returns a new pointer to a Carbon instance from an UTC timestamp. 212 | // If the location is invalid, it returns an error instead. 213 | func CreateFromTimestampUTC(timestamp int64) (*Carbon, error) { 214 | return CreateFromTimestamp(timestamp, "UTC") 215 | } 216 | 217 | // CreateFromMonthAndYear returns a new pointer to a Carbon instance from a specific month and year. 218 | // If the location is invalid, it returns an error instead. 219 | func CreateFromMonthAndYear(y int, mon time.Month, location string) (*Carbon, error) { 220 | _, _, d := Now().Date() 221 | h, m, s := Now().Clock() 222 | ns := Now().Nanosecond() 223 | 224 | return Create(y, mon, d, h, m, s, ns, location) 225 | } 226 | 227 | // Parse returns a pointer to a new carbon instance from a string 228 | // If the location is invalid, it returns an error instead. 229 | func Parse(layout, value, location string) (*Carbon, error) { 230 | l, err := time.LoadLocation(location) 231 | if err != nil { 232 | return nil, err 233 | } 234 | t, err := time.ParseInLocation(layout, value, l) 235 | if err != nil { 236 | return nil, err 237 | } 238 | 239 | return NewCarbon(t), nil 240 | } 241 | 242 | // Today returns a pointer to a new carbon instance for today 243 | // If the location is invalid, it returns an error instead. 244 | func Today(location string) (*Carbon, error) { 245 | l, err := time.LoadLocation(location) 246 | if err != nil { 247 | return nil, err 248 | } 249 | 250 | return NewCarbon(Now().In(l)), err 251 | } 252 | 253 | // Tomorrow returns a pointer to a new carbon instance for tomorrow 254 | // If the location is invalid, it returns an error instead. 255 | func Tomorrow(location string) (*Carbon, error) { 256 | c, err := Today(location) 257 | if err != nil { 258 | return nil, err 259 | } 260 | 261 | return c.AddDay(), nil 262 | } 263 | 264 | // Yesterday returns a pointer to a new carbon instance for yesterday 265 | // If the location is invalid, it returns an error instead. 266 | func Yesterday(location string) (*Carbon, error) { 267 | c, err := Today(location) 268 | if err != nil { 269 | return nil, err 270 | } 271 | 272 | return c.SubDay(), nil 273 | } 274 | 275 | // unixTimeInSeconds represents the number of seconds between Year 1 and 1970 276 | const unixTimeInSeconds = 62135596801 277 | 278 | const maxNSecs = 999999999 279 | 280 | // MaxValue returns a pointer to a new carbon instance for greatest supported date 281 | func MaxValue() *Carbon { 282 | return NewCarbon(time.Unix(math.MaxInt64-unixTimeInSeconds, maxNSecs)) 283 | } 284 | 285 | // MinValue returns a pointer to a new carbon instance for lowest supported date 286 | func MinValue() *Carbon { 287 | return NewCarbon(time.Unix(math.MinInt64+unixTimeInSeconds, 0)) 288 | } 289 | 290 | // Now returns a new Carbon instance for right now in current localtime 291 | func Now() *Carbon { 292 | if isTimeFrozen { 293 | return NewCarbon(currentFrozenTime) 294 | } 295 | 296 | return NewCarbon(time.Now()) 297 | } 298 | 299 | // NowInLocation returns a new Carbon instance for right now in given location. 300 | // The location is in IANA Time Zone database, such as "America/New_York". 301 | func NowInLocation(loc string) (*Carbon, error) { 302 | l, err := time.LoadLocation(loc) 303 | if err != nil { 304 | return nil, err 305 | } 306 | return nowIn(l), nil 307 | } 308 | 309 | func nowIn(loc *time.Location) *Carbon { 310 | return NewCarbon(Now().In(loc)) 311 | } 312 | 313 | // Copy returns a new copy of the current Carbon instance 314 | func (c *Carbon) Copy() *Carbon { 315 | return create(c.Year(), c.Month(), c.Day(), c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.Location()) 316 | } 317 | 318 | // WeekStartsAt get the starting day of the week 319 | func (c *Carbon) WeekStartsAt() time.Weekday { 320 | return c.weekStartsAt 321 | } 322 | 323 | // WeekEndsAt gets the ending day of the week 324 | func (c *Carbon) WeekEndsAt() time.Weekday { 325 | return c.weekEndsAt 326 | } 327 | 328 | // WeekendDays gets the weekend days of the week 329 | func (c *Carbon) WeekendDays() []time.Weekday { 330 | return c.weekendDays 331 | } 332 | 333 | // Quarter gets the current quarter 334 | func (c *Carbon) Quarter() int { 335 | month := c.Month() 336 | switch { 337 | case month < 4: 338 | return 1 339 | case month >= 4 && month < 7: 340 | return 2 341 | case month >= 7 && month < 10: 342 | return 3 343 | } 344 | return 4 345 | } 346 | 347 | // Age gets the age from the current instance time to now 348 | func (c *Carbon) Age() int { 349 | return int(c.DiffInYears(Now(), true)) 350 | } 351 | 352 | // DaysInMonth returns the number of days in the month 353 | func (c *Carbon) DaysInMonth() int { 354 | return c.EndOfMonth().Day() 355 | } 356 | 357 | // DaysInYear returns the number of days in the year 358 | func (c *Carbon) DaysInYear() int { 359 | if c.IsLeapYear() { 360 | return daysInLeapYear 361 | } 362 | 363 | return daysInNormalYear 364 | } 365 | 366 | // WeekOfMonth returns the week of the month 367 | func (c *Carbon) WeekOfMonth() int { 368 | w := math.Ceil(float64(c.Day() / daysPerWeek)) 369 | return int(w + 1) 370 | } 371 | 372 | // WeekOfYear returns the week of the current year. 373 | // This is an alias for time.ISOWeek 374 | func (c *Carbon) WeekOfYear() (int, int) { 375 | return c.ISOWeek() 376 | } 377 | 378 | // TimeZone gets the current timezone 379 | func (c *Carbon) TimeZone() string { 380 | return c.Location().String() 381 | } 382 | 383 | // Timestamp gets the current time since January 1, 1970 UTC 384 | func (c *Carbon) Timestamp() int64 { 385 | return c.Unix() 386 | } 387 | 388 | // String gets the current date using the previously set format 389 | func (c *Carbon) String() string { 390 | return c.Format(c.stringFormat) 391 | } 392 | 393 | // AddYears adds a year to the current time. 394 | // Positive values travel forward while negative values travel into the past 395 | func (c *Carbon) AddYears(y int) *Carbon { 396 | return NewCarbon(c.AddDate(y, 0, 0)) 397 | } 398 | 399 | // AddYear adds a year to the current time 400 | func (c *Carbon) AddYear() *Carbon { 401 | return c.AddYears(1) 402 | } 403 | 404 | // AddQuarters adds quarters to the current time. 405 | // Positive values travel forward while negative values travel into the past 406 | func (c *Carbon) AddQuarters(q int) *Carbon { 407 | return NewCarbon(c.AddDate(0, monthsPerQuarter*q, 0)) 408 | } 409 | 410 | // AddQuarter adds a quarter to the current time 411 | func (c *Carbon) AddQuarter() *Carbon { 412 | return c.AddQuarters(1) 413 | } 414 | 415 | // AddCenturies adds centuries to the time. 416 | // Positive values travels forward while negative values travels into the past 417 | func (c *Carbon) AddCenturies(cent int) *Carbon { 418 | return NewCarbon(c.AddDate(yearsPerCenturies*cent, 0, 0)) 419 | } 420 | 421 | // AddCentury adds a century to the current time 422 | func (c *Carbon) AddCentury() *Carbon { 423 | return c.AddCenturies(1) 424 | } 425 | 426 | // AddMonths adds months to the current time. 427 | // Positive value travels forward while negative values travels into the past 428 | func (c *Carbon) AddMonths(m int) *Carbon { 429 | return NewCarbon(c.AddDate(0, m, 0)) 430 | } 431 | 432 | // AddMonth adds a month to the current time 433 | func (c *Carbon) AddMonth() *Carbon { 434 | return c.AddMonths(1) 435 | } 436 | 437 | // AddSeconds adds seconds to the current time. 438 | // Positive values travels forward while negative values travels into the past. 439 | func (c *Carbon) AddSeconds(s int) *Carbon { 440 | d := time.Duration(s) * time.Second 441 | return NewCarbon(c.Add(d)) 442 | } 443 | 444 | // AddSecond adds a second to the time 445 | func (c *Carbon) AddSecond() *Carbon { 446 | return c.AddSeconds(1) 447 | } 448 | 449 | // AddDays adds a day to the current time. 450 | // Positive value travels forward while negative value travels into the past 451 | func (c *Carbon) AddDays(d int) *Carbon { 452 | return NewCarbon(c.AddDate(0, 0, d)) 453 | } 454 | 455 | // AddDay adds a day to the current time 456 | func (c *Carbon) AddDay() *Carbon { 457 | return c.AddDays(1) 458 | } 459 | 460 | // AddWeekdays adds a weekday to the current time. 461 | // Positive value travels forward while negative value travels into the past 462 | func (c *Carbon) AddWeekdays(wd int) *Carbon { 463 | d := 1 464 | if wd < 0 { 465 | wd, d = -wd, -d 466 | } 467 | t := c.Copy() 468 | for wd > 0 { 469 | t = t.AddDays(d) 470 | if t.IsWeekday() { 471 | wd-- 472 | } 473 | } 474 | 475 | return t 476 | } 477 | 478 | // AddWeekday adds a weekday to the current time 479 | func (c *Carbon) AddWeekday() *Carbon { 480 | return c.AddWeekdays(1) 481 | } 482 | 483 | // AddWeeks adds a week to the current time. 484 | // Positive value travels forward while negative value travels into the past. 485 | func (c *Carbon) AddWeeks(w int) *Carbon { 486 | return NewCarbon(c.AddDate(0, 0, daysPerWeek*w)) 487 | } 488 | 489 | // AddWeek adds a week to the current time 490 | func (c *Carbon) AddWeek() *Carbon { 491 | return c.AddWeeks(1) 492 | } 493 | 494 | // AddHours adds an hour to the current time. 495 | // Positive value travels forward while negative value travels into the past 496 | func (c *Carbon) AddHours(h int) *Carbon { 497 | d := time.Duration(h) * time.Hour 498 | 499 | return NewCarbon(c.Add(d)) 500 | } 501 | 502 | // AddHour adds an hour to the current time 503 | func (c *Carbon) AddHour() *Carbon { 504 | return c.AddHours(1) 505 | } 506 | 507 | // AddMonthsNoOverflow adds a month to the current time, not overflowing in case the 508 | // destination month has less days than the current one. 509 | // Positive value travels forward while negative value travels into the past. 510 | func (c *Carbon) AddMonthsNoOverflow(m int) *Carbon { 511 | addedDate := NewCarbon(c.AddDate(0, m, 0)) 512 | if c.Day() != addedDate.Day() { 513 | return addedDate.PreviousMonthLastDay() 514 | } 515 | 516 | return addedDate 517 | } 518 | 519 | // PreviousMonthLastDay returns the last day of the previous month 520 | func (c *Carbon) PreviousMonthLastDay() *Carbon { 521 | return NewCarbon(c.AddDate(0, 0, -c.Day())) 522 | } 523 | 524 | // AddMonthNoOverflow adds a month with no overflow to the current time 525 | func (c *Carbon) AddMonthNoOverflow() *Carbon { 526 | return c.AddMonthsNoOverflow(1) 527 | } 528 | 529 | // AddMinutes adds minutes to the current time. 530 | // Positive value travels forward while negative value travels into the past. 531 | func (c *Carbon) AddMinutes(m int) *Carbon { 532 | d := time.Duration(m) * time.Minute 533 | 534 | return NewCarbon(c.Add(d)) 535 | } 536 | 537 | // AddMinute adds a minute to the current time 538 | func (c *Carbon) AddMinute() *Carbon { 539 | return c.AddMinutes(1) 540 | } 541 | 542 | // SubYear removes a year from the current time 543 | func (c *Carbon) SubYear() *Carbon { 544 | return c.SubYears(1) 545 | } 546 | 547 | // SubYears removes years from current time 548 | func (c *Carbon) SubYears(y int) *Carbon { 549 | return c.AddYears(-1 * y) 550 | } 551 | 552 | // SubQuarter removes a quarter from the current time 553 | func (c *Carbon) SubQuarter() *Carbon { 554 | return c.SubQuarters(1) 555 | } 556 | 557 | // SubQuarters removes quarters from current time 558 | func (c *Carbon) SubQuarters(q int) *Carbon { 559 | return c.AddQuarters(-q) 560 | } 561 | 562 | // SubCentury removes a century from the current time 563 | func (c *Carbon) SubCentury() *Carbon { 564 | return c.SubCenturies(1) 565 | } 566 | 567 | // SubCenturies removes centuries from the current time 568 | func (c *Carbon) SubCenturies(cent int) *Carbon { 569 | return c.AddCenturies(-cent) 570 | } 571 | 572 | // SubMonth removes a month from the current time 573 | func (c *Carbon) SubMonth() *Carbon { 574 | return c.SubMonths(1) 575 | } 576 | 577 | // SubMonths removes months from the current time 578 | func (c *Carbon) SubMonths(m int) *Carbon { 579 | return c.AddMonths(-m) 580 | } 581 | 582 | // SubMonthNoOverflow remove a month with no overflow from the current time 583 | func (c *Carbon) SubMonthNoOverflow() *Carbon { 584 | return c.SubMonthsNoOverflow(1) 585 | } 586 | 587 | // SubMonthsNoOverflow removes months with no overflow from the current time 588 | func (c *Carbon) SubMonthsNoOverflow(m int) *Carbon { 589 | return c.AddMonthsNoOverflow(-m) 590 | } 591 | 592 | // SubDay removes a day from the current instance 593 | func (c *Carbon) SubDay() *Carbon { 594 | return c.SubDays(1) 595 | } 596 | 597 | // SubDays removes days from the current time 598 | func (c *Carbon) SubDays(d int) *Carbon { 599 | return c.AddDays(-d) 600 | } 601 | 602 | // SubWeekday removes a weekday from the current time 603 | func (c *Carbon) SubWeekday() *Carbon { 604 | return c.SubWeekdays(1) 605 | } 606 | 607 | // SubWeekdays removes a weekday from the current time 608 | func (c *Carbon) SubWeekdays(wd int) *Carbon { 609 | return c.AddWeekdays(-wd) 610 | } 611 | 612 | // SubWeek removes a week from the current time 613 | func (c *Carbon) SubWeek() *Carbon { 614 | return c.SubWeeks(1) 615 | } 616 | 617 | // SubWeeks removes weeks to the current time 618 | func (c *Carbon) SubWeeks(w int) *Carbon { 619 | return c.AddWeeks(-w) 620 | } 621 | 622 | // SubHour removes an hour from the current time 623 | func (c *Carbon) SubHour() *Carbon { 624 | return c.SubHours(1) 625 | } 626 | 627 | // SubHours removes hours from the current time 628 | func (c *Carbon) SubHours(h int) *Carbon { 629 | return c.AddHours(-h) 630 | } 631 | 632 | // SubMinute removes a minute from the current time 633 | func (c *Carbon) SubMinute() *Carbon { 634 | return c.SubMinutes(1) 635 | } 636 | 637 | // SubMinutes removes minutes from the current time 638 | func (c *Carbon) SubMinutes(m int) *Carbon { 639 | return c.AddMinutes(-m) 640 | } 641 | 642 | // SubSecond removes a second from the current time 643 | func (c *Carbon) SubSecond() *Carbon { 644 | return c.SubSeconds(1) 645 | } 646 | 647 | // SubSeconds removes seconds from the current time 648 | func (c *Carbon) SubSeconds(s int) *Carbon { 649 | return c.AddSeconds(-s) 650 | } 651 | 652 | // SetYear sets the year of the current time 653 | func (c *Carbon) SetYear(y int) { 654 | c.Time = time.Date(y, c.Month(), c.Day(), c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.Location()) 655 | } 656 | 657 | // SetMonth sets the month of the current time 658 | func (c *Carbon) SetMonth(m time.Month) { 659 | c.Time = time.Date(c.Year(), m, c.Day(), c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.Location()) 660 | } 661 | 662 | // SetDay sets the day of the current time 663 | func (c *Carbon) SetDay(d int) { 664 | c.Time = time.Date(c.Year(), c.Month(), d, c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.Location()) 665 | } 666 | 667 | // SetHour sets the hour of the current time 668 | func (c *Carbon) SetHour(h int) { 669 | c.Time = time.Date(c.Year(), c.Month(), c.Day(), h, c.Minute(), c.Second(), c.Nanosecond(), c.Location()) 670 | } 671 | 672 | // SetMinute sets the minute of the current time 673 | func (c *Carbon) SetMinute(m int) { 674 | c.Time = time.Date(c.Year(), c.Month(), c.Day(), c.Hour(), m, c.Second(), c.Nanosecond(), c.Location()) 675 | } 676 | 677 | // SetSecond sets the second of the current time 678 | func (c *Carbon) SetSecond(s int) { 679 | c.Time = time.Date(c.Year(), c.Month(), c.Day(), c.Hour(), c.Minute(), s, c.Nanosecond(), c.Location()) 680 | } 681 | 682 | // SetDate sets only the date of the current time 683 | func (c *Carbon) SetDate(y int, m time.Month, d int) { 684 | c.Time = time.Date(y, m, d, c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.Location()) 685 | } 686 | 687 | // SetDateTime sets the date and the time 688 | func (c *Carbon) SetDateTime(y int, mon time.Month, d, h, m, s int) { 689 | c.Time = time.Date(y, mon, d, h, m, s, c.Nanosecond(), c.Location()) 690 | } 691 | 692 | // SetTimeFromTimeString receives a string and sets the current time 693 | // It accepts the following formats: "hh:mm:ss", "hh:mm" and "hh" 694 | func (c *Carbon) SetTimeFromTimeString(timeString string) error { 695 | layouts := []string{ 696 | TimeFormat, 697 | HourMinuteFormat, 698 | HourFormat, 699 | } 700 | 701 | var t time.Time 702 | var err error 703 | for i, layout := range layouts { 704 | t, err = time.Parse(layout, timeString) 705 | if err == nil { 706 | h, m, s := t.Clock() 707 | switch i { 708 | case 1: 709 | s = c.Second() 710 | case 2: 711 | m, s = c.Minute(), c.Second() 712 | } 713 | c.SetHour(h) 714 | c.SetMinute(m) 715 | c.SetSecond(s) 716 | return nil 717 | } 718 | } 719 | 720 | return errors.New("only supports hh:mm:ss, hh:mm and hh formats") 721 | } 722 | 723 | // SetWeekEndsAt sets the last day of week 724 | func (c *Carbon) SetWeekEndsAt(wd time.Weekday) { 725 | c.weekEndsAt = wd 726 | } 727 | 728 | // SetWeekStartsAt sets the first day of week 729 | func (c *Carbon) SetWeekStartsAt(wd time.Weekday) { 730 | c.weekStartsAt = wd 731 | } 732 | 733 | // SetWeekendDays sets the weekend days 734 | func (c *Carbon) SetWeekendDays(wds []time.Weekday) { 735 | c.weekendDays = wds 736 | } 737 | 738 | // SetTimestamp sets the current time given a timestamp 739 | func (c *Carbon) SetTimestamp(sec int64) { 740 | c.Time = time.Unix(sec, 0).In(c.Location()) 741 | } 742 | 743 | // SetTimeZone sets the location from a string 744 | // If the location is invalid, it returns an error instead. 745 | func (c *Carbon) SetTimeZone(name string) error { 746 | loc, err := time.LoadLocation(name) 747 | if err != nil { 748 | return err 749 | } 750 | c.Time = time.Date(c.Year(), c.Month(), c.Day(), c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), loc) 751 | 752 | return nil 753 | } 754 | 755 | // ResetStringFormat changes the format to the DefaultFormat 756 | func (c *Carbon) ResetStringFormat() { 757 | c.stringFormat = DefaultFormat 758 | } 759 | 760 | // SetStringFormat formats the current time with the set format string 761 | func (c *Carbon) SetStringFormat(format string) { 762 | c.stringFormat = format 763 | } 764 | 765 | // DateString return the current time in Y-m-d format 766 | func (c *Carbon) DateString() string { 767 | return c.Format(DateFormat) 768 | } 769 | 770 | // FormattedDateString returns the current time as a readable date 771 | func (c *Carbon) FormattedDateString() string { 772 | return c.Format(FormattedDateFormat) 773 | } 774 | 775 | // TimeString returns the current time in hh:mm:ss format 776 | func (c *Carbon) TimeString() string { 777 | return c.Format(TimeFormat) 778 | } 779 | 780 | // DateTimeString returns the current time in Y-m-d hh:mm:ss format 781 | func (c *Carbon) DateTimeString() string { 782 | return c.Format(DefaultFormat) 783 | } 784 | 785 | // DayDateTimeString returns the current time with a day, date and time format 786 | func (c *Carbon) DayDateTimeString() string { 787 | return c.Format(DayDateTimeFormat) 788 | } 789 | 790 | // AtomString formats the current time to a Atom date format 791 | func (c *Carbon) AtomString() string { 792 | return c.Format(RFC3339Format) 793 | } 794 | 795 | // CookieString formats the current time to a Cookie date format 796 | func (c *Carbon) CookieString() string { 797 | return c.Format(CookieFormat) 798 | } 799 | 800 | // ISO8601String returns the current time in ISO8601 format 801 | func (c *Carbon) ISO8601String() string { 802 | return c.Format(RFC3339Format) 803 | } 804 | 805 | // RFC822String returns the current time in RFC 822 format 806 | func (c *Carbon) RFC822String() string { 807 | return c.Format(RFC822Format) 808 | } 809 | 810 | // RFC850String returns the current time in RFC 850 format 811 | func (c *Carbon) RFC850String() string { 812 | return c.Format(time.RFC850) 813 | } 814 | 815 | // RFC1036String returns the current time in RFC 1036 format 816 | func (c *Carbon) RFC1036String() string { 817 | return c.Format(RFC1036Format) 818 | } 819 | 820 | // RFC1123String returns the current time in RFC 1123 format 821 | func (c *Carbon) RFC1123String() string { 822 | return c.Format(time.RFC1123Z) 823 | } 824 | 825 | // RFC2822String returns the current time in RFC 2822 format 826 | func (c *Carbon) RFC2822String() string { 827 | return c.Format(RFC2822Format) 828 | } 829 | 830 | // RFC3339String returns the current time in RFC 3339 format 831 | func (c *Carbon) RFC3339String() string { 832 | return c.Format(RFC3339Format) 833 | } 834 | 835 | // RSSString returns the current time for RSS format 836 | func (c *Carbon) RSSString() string { 837 | return c.Format(RSSFormat) 838 | } 839 | 840 | // W3CString returns the current time for WWW Consortium format 841 | func (c *Carbon) W3CString() string { 842 | return c.Format(RFC3339Format) 843 | } 844 | 845 | // IsWeekday determines if the current time is a weekday 846 | func (c *Carbon) IsWeekday() bool { 847 | return !c.IsWeekend() 848 | } 849 | 850 | // IsWeekend determines if the current time is a weekend day 851 | func (c *Carbon) IsWeekend() bool { 852 | d := c.Weekday() 853 | for _, wd := range c.WeekendDays() { 854 | if d == wd { 855 | return true 856 | } 857 | } 858 | 859 | return false 860 | } 861 | 862 | // IsYesterday determines if the current time is yesterday 863 | func (c *Carbon) IsYesterday() bool { 864 | n := Now().SubDay() 865 | 866 | return c.IsSameDay(n) 867 | } 868 | 869 | // IsToday determines if the current time is today 870 | func (c *Carbon) IsToday() bool { 871 | return c.IsSameDay(Now()) 872 | } 873 | 874 | // IsTomorrow determines if the current time is tomorrow 875 | func (c *Carbon) IsTomorrow() bool { 876 | n := Now().AddDay() 877 | 878 | return c.IsSameDay(n) 879 | } 880 | 881 | // IsFuture determines if the current time is in the future, ie. greater (after) than now 882 | func (c *Carbon) IsFuture() bool { 883 | return c.After(Now().Time) 884 | } 885 | 886 | // IsPast determines if the current time is in the past, ie. less (before) than now 887 | func (c *Carbon) IsPast() bool { 888 | return c.Before(Now().Time) 889 | } 890 | 891 | // IsLeapYear determines if current current time is a leap year 892 | func (c *Carbon) IsLeapYear() bool { 893 | y := c.Year() 894 | if (y%4 == 0 && y%100 != 0) || y%400 == 0 { 895 | return true 896 | } 897 | 898 | return false 899 | } 900 | 901 | // IsLongYear determines if the instance is a long year 902 | func (c *Carbon) IsLongYear() bool { 903 | carb := create(c.Year(), time.December, 31, 0, 0, 0, 0, c.Location()) 904 | _, w := carb.WeekOfYear() 905 | 906 | return w == weeksPerLongYear 907 | } 908 | 909 | // IsSameAs compares the formatted values of the two dates. 910 | // If passed date is nil, compares against today 911 | func (c *Carbon) IsSameAs(format string, carb *Carbon) bool { 912 | if carb == nil { 913 | return c.Format(DefaultFormat) == Now().Format(DefaultFormat) 914 | } 915 | 916 | return c.Format(DefaultFormat) == carb.Format(DefaultFormat) 917 | } 918 | 919 | // IsCurrentYear determines if the current time is in the current year 920 | func (c *Carbon) IsCurrentYear() bool { 921 | return c.Year() == Now().Year() 922 | } 923 | 924 | // IsSameYear checks if the passed in date is in the same year as the current time year. 925 | // If passed date is nil, compares against today 926 | func (c *Carbon) IsSameYear(carb *Carbon) bool { 927 | if carb == nil { 928 | return c.Year() == nowIn(c.Location()).Year() 929 | } 930 | 931 | return c.Year() == carb.Year() 932 | } 933 | 934 | // IsCurrentMonth determines if the current time is in the current month 935 | func (c *Carbon) IsCurrentMonth() bool { 936 | return c.Month() == Now().Month() 937 | } 938 | 939 | // IsSameMonth checks if the passed in date is in the same month as the current month 940 | // If passed date is nil, compares against today 941 | func (c *Carbon) IsSameMonth(carb *Carbon, sameYear bool) bool { 942 | m := nowIn(c.Location()).Month() 943 | if carb != nil { 944 | m = carb.Month() 945 | } 946 | if sameYear { 947 | return c.IsSameYear(carb) && c.Month() == m 948 | } 949 | 950 | return c.Month() == m 951 | } 952 | 953 | // IsSameDay checks if the passed in date is the same day as the current day. 954 | // If passed date is nil, compares against today 955 | func (c *Carbon) IsSameDay(carb *Carbon) bool { 956 | n := nowIn(c.Location()) 957 | if carb != nil { 958 | n = carb 959 | } 960 | 961 | return c.Year() == n.Year() && c.Month() == n.Month() && c.Day() == n.Day() 962 | } 963 | 964 | // IsSunday checks if this day is a Sunday. 965 | func (c *Carbon) IsSunday() bool { 966 | return c.Weekday() == time.Sunday 967 | } 968 | 969 | // IsMonday checks if this day is a Monday. 970 | func (c *Carbon) IsMonday() bool { 971 | return c.Weekday() == time.Monday 972 | } 973 | 974 | // IsTuesday checks if this day is a Tuesday. 975 | func (c *Carbon) IsTuesday() bool { 976 | return c.Weekday() == time.Tuesday 977 | } 978 | 979 | // IsWednesday checks if this day is a Wednesday. 980 | func (c *Carbon) IsWednesday() bool { 981 | return c.Weekday() == time.Wednesday 982 | } 983 | 984 | // IsThursday checks if this day is a Thursday. 985 | func (c *Carbon) IsThursday() bool { 986 | return c.Weekday() == time.Thursday 987 | } 988 | 989 | // IsFriday checks if this day is a Friday. 990 | func (c *Carbon) IsFriday() bool { 991 | return c.Weekday() == time.Friday 992 | } 993 | 994 | // IsSaturday checks if this day is a Saturday. 995 | func (c *Carbon) IsSaturday() bool { 996 | return c.Weekday() == time.Saturday 997 | } 998 | 999 | // IsLastWeek returns true is the date is within last week 1000 | func (c *Carbon) IsLastWeek() bool { 1001 | secondsInWeek := float64(secondsInWeek) 1002 | difference := Now().Sub(c.Time) 1003 | if difference.Seconds() > 0 && difference.Seconds() < secondsInWeek { 1004 | return true 1005 | } 1006 | 1007 | return false 1008 | } 1009 | 1010 | // IsLastMonth returns true is the date is within last month 1011 | func (c *Carbon) IsLastMonth() bool { 1012 | now := Now() 1013 | 1014 | monthDifference := now.Month() - c.Month() 1015 | 1016 | if absValue(true, int64(monthDifference)) != 1 { 1017 | return false 1018 | } 1019 | 1020 | if now.UnixNano() > c.UnixNano() && monthDifference == 1 { 1021 | return true 1022 | } 1023 | 1024 | return false 1025 | } 1026 | 1027 | // Eq determines if the current carbon is equal to another 1028 | func (c *Carbon) Eq(carb *Carbon) bool { 1029 | return c.Equal(carb.Time) 1030 | } 1031 | 1032 | // EqualTo determines if the current carbon is equal to another 1033 | func (c *Carbon) EqualTo(carb *Carbon) bool { 1034 | return c.Eq(carb) 1035 | } 1036 | 1037 | // Ne determines if the current carbon is not equal to another 1038 | func (c *Carbon) Ne(carb *Carbon) bool { 1039 | return !c.Eq(carb) 1040 | } 1041 | 1042 | // NotEqualTo determines if the current carbon is not equal to another 1043 | func (c *Carbon) NotEqualTo(carb *Carbon) bool { 1044 | return c.Ne(carb) 1045 | } 1046 | 1047 | // Gt determines if the current carbon is greater (after) than another 1048 | func (c *Carbon) Gt(carb *Carbon) bool { 1049 | return c.After(carb.Time) 1050 | } 1051 | 1052 | // GreaterThan determines if the current carbon is greater (after) than another 1053 | func (c *Carbon) GreaterThan(carb *Carbon) bool { 1054 | return c.Gt(carb) 1055 | } 1056 | 1057 | // Gte determines if the instance is greater (after) than or equal to another 1058 | func (c *Carbon) Gte(carb *Carbon) bool { 1059 | return c.Gt(carb) || c.Eq(carb) 1060 | } 1061 | 1062 | // GreaterThanOrEqualTo determines if the instance is greater (after) than or equal to another 1063 | func (c *Carbon) GreaterThanOrEqualTo(carb *Carbon) bool { 1064 | return c.Gte(carb) || c.Eq(carb) 1065 | } 1066 | 1067 | // Lt determines if the instance is less (before) than another 1068 | func (c *Carbon) Lt(carb *Carbon) bool { 1069 | return c.Before(carb.Time) 1070 | } 1071 | 1072 | // LessThan determines if the instance is less (before) than another 1073 | func (c *Carbon) LessThan(carb *Carbon) bool { 1074 | return c.Lt(carb) 1075 | } 1076 | 1077 | // Lte determines if the instance is less (before) or equal to another 1078 | func (c *Carbon) Lte(carb *Carbon) bool { 1079 | return c.Lt(carb) || c.Eq(carb) 1080 | } 1081 | 1082 | // LessThanOrEqualTo determines if the instance is less (before) or equal to another 1083 | func (c *Carbon) LessThanOrEqualTo(carb *Carbon) bool { 1084 | return c.Lte(carb) 1085 | } 1086 | 1087 | // Between determines if the current instance is between two others 1088 | // eq Indicates if a > and < comparison should be used or <= or >= 1089 | func (c *Carbon) Between(a, b *Carbon, eq bool) bool { 1090 | if a.Gt(b) { 1091 | a, b = swap(a, b) 1092 | } 1093 | if eq { 1094 | return c.Gte(a) && c.Lte(b) 1095 | } 1096 | 1097 | return c.Gt(a) && c.Lt(b) 1098 | } 1099 | 1100 | // Closest returns the closest date from the current time 1101 | func (c *Carbon) Closest(a, b *Carbon) *Carbon { 1102 | if c.DiffInSeconds(a, true) < c.DiffInSeconds(b, true) { 1103 | return a 1104 | } 1105 | 1106 | return b 1107 | } 1108 | 1109 | // Farthest returns the farthest date from the current time 1110 | func (c *Carbon) Farthest(a, b *Carbon) *Carbon { 1111 | if c.DiffInSeconds(a, true) > c.DiffInSeconds(b, true) { 1112 | return a 1113 | } 1114 | 1115 | return b 1116 | } 1117 | 1118 | // Min returns the minimum instance between a given instance and the current instance 1119 | func (c *Carbon) Min(carb *Carbon) *Carbon { 1120 | if carb == nil { 1121 | carb = nowIn(c.Location()) 1122 | } 1123 | if c.Lt(carb) { 1124 | return c 1125 | } 1126 | 1127 | return carb 1128 | } 1129 | 1130 | // Minimum returns the minimum instance between a given instance and the current instance 1131 | func (c *Carbon) Minimum(carb *Carbon) *Carbon { 1132 | return c.Min(carb) 1133 | } 1134 | 1135 | // Max returns the maximum instance between a given instance and the current instance 1136 | func (c *Carbon) Max(carb *Carbon) *Carbon { 1137 | if carb == nil { 1138 | carb = nowIn(c.Location()) 1139 | } 1140 | 1141 | if c.Gt(carb) { 1142 | return c 1143 | } 1144 | 1145 | return carb 1146 | } 1147 | 1148 | // Maximum returns the maximum instance between a given instance and the current instance 1149 | func (c *Carbon) Maximum(carb *Carbon) *Carbon { 1150 | return c.Max(carb) 1151 | } 1152 | 1153 | // DiffInYears returns the difference in years 1154 | func (c *Carbon) DiffInYears(carb *Carbon, abs bool) int64 { 1155 | if carb == nil { 1156 | carb = nowIn(c.Location()) 1157 | } 1158 | 1159 | if c.Year() == carb.Year() { 1160 | return 0 1161 | } 1162 | 1163 | start := NewCarbon(c.Time) 1164 | end := NewCarbon(carb.Time) 1165 | if end.UnixNano() < start.UnixNano() { 1166 | aux := start 1167 | start = end 1168 | end = aux 1169 | } 1170 | 1171 | yearsAmmount := int64(end.Year()-start.Year()) - 1 1172 | 1173 | start.SetYear(end.Year()) 1174 | 1175 | if start.UnixNano() <= end.UnixNano() { 1176 | yearsAmmount++ 1177 | } 1178 | 1179 | return absValue(abs, yearsAmmount) 1180 | } 1181 | 1182 | // DiffInMonths returns the difference in months 1183 | func (c *Carbon) DiffInMonths(carb *Carbon, abs bool) int64 { 1184 | if carb == nil { 1185 | carb = nowIn(c.Location()) 1186 | } 1187 | 1188 | cAux := c.Copy() 1189 | carbAux := carb.Copy() 1190 | if cAux.Location() != carbAux.Location() { 1191 | cAux = NewCarbon(cAux.In(time.UTC)) 1192 | carbAux = NewCarbon(carbAux.In(time.UTC)) 1193 | } 1194 | 1195 | return calculateDiffInMonths(cAux, carbAux, abs) 1196 | } 1197 | 1198 | func calculateDiffInMonths(c *Carbon, carb *Carbon, abs bool) int64 { 1199 | if c.Month() == carb.Month() && c.Year() == carb.Year() { 1200 | return 0 1201 | } 1202 | 1203 | diffInDays := c.DiffInDays(carb, false) 1204 | 1205 | end := c.Copy() 1206 | start := carb.Copy() 1207 | reg := -int64(1) 1208 | 1209 | if diffInDays > 0 { 1210 | end = carb.Copy() 1211 | start = c.Copy() 1212 | reg = int64(1) 1213 | } 1214 | 1215 | months := calculateFromMonthToMonth(start, end, 0) 1216 | 1217 | return absValue(abs, int64(months*reg)) 1218 | } 1219 | 1220 | func calculateFromMonthToMonth(start *Carbon, end *Carbon, months int64) int64 { 1221 | date := start.AddDays(start.DaysInMonth()) 1222 | diffInDays := date.DiffInDays(end, false) 1223 | diffInSeconds := date.DiffInSeconds(end, false) 1224 | 1225 | if diffInDays < 0 || diffInDays == 0 && diffInSeconds < 0 { 1226 | return months 1227 | } 1228 | 1229 | months += 1 1230 | 1231 | return calculateFromMonthToMonth(date, end, months) 1232 | } 1233 | 1234 | func (c *Carbon) hasRemainingHours(carb *Carbon) bool { 1235 | totalHr := int64(c.DaysInMonth() * hoursPerDay) 1236 | cHr := c.StartOfMonth().DiffInHours(c, false) 1237 | remainHr := totalHr - cHr 1238 | spentInHr := carb.StartOfMonth().DiffInHours(carb, false) 1239 | 1240 | return remainHr+spentInHr >= totalHr 1241 | } 1242 | 1243 | // DiffDurationInString returns the duration difference in string format 1244 | func (c *Carbon) DiffDurationInString(carb *Carbon) string { 1245 | if carb == nil { 1246 | carb = nowIn(c.Location()) 1247 | } 1248 | 1249 | return strings.Replace(carb.Sub(c.Time).String(), "-", "", 1) 1250 | } 1251 | 1252 | // DiffInWeeks returns the difference in weeks 1253 | func (c *Carbon) DiffInWeeks(carb *Carbon, abs bool) int64 { 1254 | if carb == nil { 1255 | carb = nowIn(c.Location()) 1256 | } 1257 | return c.DiffInDays(carb, abs) / daysPerWeek 1258 | } 1259 | 1260 | // DiffInDays returns the difference in days 1261 | func (c *Carbon) DiffInDays(carb *Carbon, abs bool) int64 { 1262 | if carb == nil { 1263 | carb = nowIn(c.Location()) 1264 | } 1265 | return c.DiffInHours(carb, abs) / hoursPerDay 1266 | } 1267 | 1268 | // DiffInNights returns the difference in nights 1269 | func (c *Carbon) DiffInNights(carb *Carbon, abs bool) int64 { 1270 | if carb == nil { 1271 | carb = nowIn(c.Location()) 1272 | } 1273 | return c.DiffInDays(carb, abs) 1274 | } 1275 | 1276 | // Filter represents a predicate used for filtering diffs 1277 | type Filter func(*Carbon) bool 1278 | 1279 | // dayDuration reprensets a day in time.Duration format 1280 | const dayDuration = time.Hour * hoursPerDay 1281 | 1282 | // DiffInDaysFiltered returns the difference in days using a filter 1283 | func (c *Carbon) DiffInDaysFiltered(f Filter, carb *Carbon, abs bool) int64 { 1284 | return c.DiffFiltered(dayDuration, f, carb, abs) 1285 | } 1286 | 1287 | // DiffInHoursFiltered returns the difference in hours using a filter 1288 | func (c *Carbon) DiffInHoursFiltered(f Filter, carb *Carbon, abs bool) int64 { 1289 | return c.DiffFiltered(time.Hour, f, carb, abs) 1290 | } 1291 | 1292 | // DiffInWeekdays returns the difference in weekdays 1293 | func (c *Carbon) DiffInWeekdays(carb *Carbon, abs bool) int64 { 1294 | f := func(t *Carbon) bool { 1295 | return t.IsWeekday() 1296 | } 1297 | 1298 | return c.DiffFiltered(dayDuration, f, carb, abs) 1299 | } 1300 | 1301 | // DiffInWeekendDays returns the difference in weekend days using a filter 1302 | func (c *Carbon) DiffInWeekendDays(carb *Carbon, abs bool) int64 { 1303 | f := func(t *Carbon) bool { 1304 | return t.IsWeekend() 1305 | } 1306 | 1307 | return c.DiffFiltered(dayDuration, f, carb, abs) 1308 | } 1309 | 1310 | // DiffFiltered returns the difference by the given duration using a filter 1311 | func (c *Carbon) DiffFiltered(duration time.Duration, f Filter, carb *Carbon, abs bool) int64 { 1312 | if carb == nil { 1313 | carb = nowIn(c.Location()) 1314 | } 1315 | if c.IsSameDay(carb) { 1316 | return 0 1317 | } 1318 | 1319 | inverse := false 1320 | var counter int64 1321 | s := int64(duration.Seconds()) 1322 | start, end := c.Copy(), carb.Copy() 1323 | if start.Gt(end) { 1324 | start, end = swap(start, end) 1325 | inverse = true 1326 | } 1327 | for start.DiffInSeconds(end, true)/s > 0 { 1328 | if f(end) { 1329 | counter++ 1330 | } 1331 | end = NewCarbon(end.Add(-duration)) 1332 | } 1333 | if inverse { 1334 | counter = -counter 1335 | } 1336 | 1337 | return absValue(abs, counter) 1338 | } 1339 | 1340 | // DiffInHours returns the difference in hours 1341 | func (c *Carbon) DiffInHours(d *Carbon, abs bool) int64 { 1342 | return c.DiffInMinutes(d, abs) / minutesPerHour 1343 | } 1344 | 1345 | // DiffInMinutes returns the difference in minutes 1346 | func (c *Carbon) DiffInMinutes(d *Carbon, abs bool) int64 { 1347 | return c.DiffInSeconds(d, abs) / secondsPerMinute 1348 | } 1349 | 1350 | // DiffInSeconds returns the difference in seconds 1351 | func (c *Carbon) DiffInSeconds(carb *Carbon, abs bool) int64 { 1352 | if carb == nil { 1353 | carb = nowIn(c.Location()) 1354 | } 1355 | diff := carb.Timestamp() - c.Timestamp() 1356 | 1357 | return absValue(abs, diff) 1358 | } 1359 | 1360 | // SecondsSinceMidnight returns the number of seconds since midnight. 1361 | func (c *Carbon) SecondsSinceMidnight() int { 1362 | startOfDay := c.StartOfDay() 1363 | 1364 | return int(c.DiffInSeconds(startOfDay, true)) 1365 | } 1366 | 1367 | // SecondsUntilEndOfDay returns the number of seconds until 23:59:59. 1368 | func (c *Carbon) SecondsUntilEndOfDay() int { 1369 | dayEnd := c.EndOfDay() 1370 | 1371 | return int(c.DiffInSeconds(dayEnd, true)) 1372 | } 1373 | 1374 | // absValue returns the abs value if needed 1375 | func absValue(needsAbs bool, value int64) int64 { 1376 | if needsAbs && value < 0 { 1377 | return -value 1378 | } 1379 | 1380 | return value 1381 | } 1382 | 1383 | func swap(a, b *Carbon) (*Carbon, *Carbon) { 1384 | return b, a 1385 | } 1386 | 1387 | // DiffForHumans returns the difference in a human readable format in the current locale. 1388 | // When comparing a value in the past to default now: 1389 | // 1 hour ago 1390 | // 5 months ago 1391 | // When comparing a value in the future to default now: 1392 | // 1 hour from now 1393 | // 5 months from now 1394 | // When comparing a value in the past to another value: 1395 | // 1 hour before 1396 | // 5 months before 1397 | // When comparing a value in the future to another value: 1398 | // 1 hour after 1399 | // 5 months after 1400 | func (c *Carbon) DiffForHumans(d *Carbon, abs, absolute, short bool) (string, error) { 1401 | isNow := (d == nil) 1402 | if isNow { 1403 | d = Now() 1404 | } 1405 | 1406 | var unit string 1407 | var count int64 1408 | 1409 | switch true { 1410 | case c.DiffInYears(d, abs) > 0: 1411 | if short { 1412 | unit = "y" 1413 | } else { 1414 | unit = "year" 1415 | } 1416 | count = c.DiffInYears(d, abs) 1417 | break 1418 | 1419 | case c.DiffInMonths(d, abs) > 0: 1420 | if short { 1421 | unit = "m" 1422 | } else { 1423 | unit = "month" 1424 | } 1425 | count = c.DiffInMonths(d, abs) 1426 | break 1427 | 1428 | case c.DiffInDays(d, abs) > 0: 1429 | if short { 1430 | unit = "d" 1431 | } else { 1432 | unit = "day" 1433 | } 1434 | count = c.DiffInDays(d, abs) 1435 | if count >= daysPerWeek { 1436 | if short { 1437 | unit = "w" 1438 | } else { 1439 | unit = "week" 1440 | } 1441 | count = int64(count / daysPerWeek) 1442 | } 1443 | break 1444 | 1445 | case c.DiffInHours(d, abs) > 0: 1446 | if short { 1447 | unit = "h" 1448 | } else { 1449 | unit = "hour" 1450 | } 1451 | count = c.DiffInHours(d, abs) 1452 | break 1453 | 1454 | case c.DiffInMinutes(d, abs) > 0: 1455 | if short { 1456 | unit = "min" 1457 | } else { 1458 | unit = "minute" 1459 | } 1460 | count = c.DiffInMinutes(d, abs) 1461 | break 1462 | 1463 | default: 1464 | if short { 1465 | unit = "s" 1466 | } else { 1467 | unit = "second" 1468 | } 1469 | count = c.DiffInSeconds(d, abs) 1470 | break 1471 | } 1472 | 1473 | if count == 0 { 1474 | count = 1 1475 | } 1476 | 1477 | t, err := c.Translator.chooseUnit(unit, count) 1478 | if err != nil { 1479 | return "", err 1480 | } 1481 | 1482 | if absolute { 1483 | return t, nil 1484 | } 1485 | 1486 | isFuture := c.GreaterThan(d) 1487 | 1488 | var transID string 1489 | if isNow { 1490 | if isFuture { 1491 | transID = "from_now" 1492 | } else { 1493 | transID = "ago" 1494 | } 1495 | } else { 1496 | if isFuture { 1497 | transID = "after" 1498 | } else { 1499 | transID = "before" 1500 | } 1501 | } 1502 | 1503 | /* TODO 1504 | // Some langs have special pluralization for past and future tense. 1505 | // tryKeyExists := unit + "_" + transID 1506 | if tryKeyExists != c.Translator.Choose(tryKeyExists, count) { 1507 | time, _ = c.Translator.Choose(tryKeyExists, count) 1508 | } 1509 | */ 1510 | 1511 | return c.Translator.chooseTrans(transID, t), nil 1512 | } 1513 | 1514 | // StartOfDay returns the time at 00:00:00 of the same day 1515 | func (c *Carbon) StartOfDay() *Carbon { 1516 | return create(c.Year(), c.Month(), c.Day(), 0, 0, 0, 0, c.Location()) 1517 | } 1518 | 1519 | // EndOfDay returns the time at 23:59:59 of the same day 1520 | func (c *Carbon) EndOfDay() *Carbon { 1521 | return create(c.Year(), c.Month(), c.Day(), 23, 59, 59, maxNSecs, c.Location()) 1522 | } 1523 | 1524 | // StartOfMonth returns the date on the first day of the month and the time to 00:00:00 1525 | func (c *Carbon) StartOfMonth() *Carbon { 1526 | return create(c.Year(), c.Month(), 1, 0, 0, 0, 0, c.Location()) 1527 | } 1528 | 1529 | // EndOfMonth returns the date at the end of the month and time at 23:59:59 1530 | func (c *Carbon) EndOfMonth() *Carbon { 1531 | return create(c.Year(), c.Month()+1, 0, 23, 59, 59, maxNSecs, c.Location()) 1532 | } 1533 | 1534 | // StartOfQuarter returns the date at the first day of the quarter and time at 00:00:00 1535 | func (c *Carbon) StartOfQuarter() *Carbon { 1536 | month := time.Month((c.Quarter()-1)*monthsPerQuarter + 1) 1537 | 1538 | return create(c.Year(), time.Month(month), 1, 0, 0, 0, 0, c.Location()) 1539 | } 1540 | 1541 | // EndOfQuarter returns the date at end of the quarter and time at 23:59:59 1542 | func (c *Carbon) EndOfQuarter() *Carbon { 1543 | return c.StartOfQuarter().AddMonths(monthsPerQuarter - 1).EndOfMonth() 1544 | } 1545 | 1546 | // StartOfYear returns the date at the first day of the year and the time at 00:00:00 1547 | func (c *Carbon) StartOfYear() *Carbon { 1548 | return create(c.Year(), time.January, 1, 0, 0, 0, 0, c.Location()) 1549 | } 1550 | 1551 | // EndOfYear returns the date at end of the year and time to 23:59:59 1552 | func (c *Carbon) EndOfYear() *Carbon { 1553 | return create(c.Year(), time.December, 31, 23, 59, 59, maxNSecs, c.Location()) 1554 | } 1555 | 1556 | // StartOfDecade returns the date at the first day of the decade and time at 00:00:00 1557 | func (c *Carbon) StartOfDecade() *Carbon { 1558 | year := c.Year() - c.Year()%yearsPerDecade 1559 | 1560 | return create(year, time.January, 1, 0, 0, 0, 0, c.Location()) 1561 | } 1562 | 1563 | // EndOfDecade returns the date at the end of the decade and time at 23:59:59 1564 | func (c *Carbon) EndOfDecade() *Carbon { 1565 | year := c.Year() - c.Year()%yearsPerDecade + yearsPerDecade - 1 1566 | 1567 | return create(year, time.December, 31, 23, 59, 59, maxNSecs, c.Location()) 1568 | } 1569 | 1570 | // StartOfCentury returns the date of the first day of the century at 00:00:00 1571 | func (c *Carbon) StartOfCentury() *Carbon { 1572 | year := c.Year() - c.Year()%yearsPerCenturies 1573 | 1574 | return create(year, time.January, 1, 0, 0, 0, 0, c.Location()) 1575 | } 1576 | 1577 | // EndOfCentury returns the date of the end of the century at 23:59:59 1578 | func (c *Carbon) EndOfCentury() *Carbon { 1579 | year := c.Year() - 1 - c.Year()%yearsPerCenturies + yearsPerCenturies 1580 | 1581 | return create(year, time.December, 31, 23, 59, 59, maxNSecs, c.Location()) 1582 | } 1583 | 1584 | // StartOfWeek returns the date of the first day of week at 00:00:00 1585 | func (c *Carbon) StartOfWeek() *Carbon { 1586 | if c.Weekday() == c.WeekStartsAt() { 1587 | return c.StartOfDay() 1588 | } 1589 | 1590 | return c.Previous(c.WeekStartsAt()) 1591 | } 1592 | 1593 | // EndOfWeek returns the date of the last day of the week at 23:59:59 1594 | func (c *Carbon) EndOfWeek() *Carbon { 1595 | if c.Weekday() == c.WeekEndsAt() { 1596 | return c.EndOfDay() 1597 | } 1598 | 1599 | return c.Next(c.WeekEndsAt()).EndOfDay() 1600 | } 1601 | 1602 | // Next changes the time to the next occurrence of a given day of the week 1603 | func (c *Carbon) Next(wd time.Weekday) *Carbon { 1604 | c = c.AddDay() 1605 | for c.Weekday() != wd { 1606 | c = c.AddDay() 1607 | } 1608 | 1609 | return c.StartOfDay() 1610 | } 1611 | 1612 | // NextWeekday goes forward to the next weekday 1613 | func (c *Carbon) NextWeekday() *Carbon { 1614 | return c.AddWeekday() 1615 | } 1616 | 1617 | // PreviousWeekday goes back to the previous weekday 1618 | func (c *Carbon) PreviousWeekday() *Carbon { 1619 | return c.SubWeekday() 1620 | } 1621 | 1622 | // NextWeekendDay goes forward to the next weekend day 1623 | func (c *Carbon) NextWeekendDay() *Carbon { 1624 | c = c.AddDay() 1625 | for !c.IsWeekend() { 1626 | c = c.AddDay() 1627 | } 1628 | 1629 | return c 1630 | } 1631 | 1632 | // PreviousWeekendDay goes back to the previous weekend day 1633 | func (c *Carbon) PreviousWeekendDay() *Carbon { 1634 | c = c.SubDay() 1635 | for !c.IsWeekend() { 1636 | c = c.SubDay() 1637 | } 1638 | 1639 | return c 1640 | } 1641 | 1642 | // Previous changes the time to the previous occurrence of a given day of the week 1643 | func (c *Carbon) Previous(wd time.Weekday) *Carbon { 1644 | c = c.SubDay() 1645 | for c.Weekday() != wd { 1646 | c = c.SubDay() 1647 | } 1648 | 1649 | return c.StartOfDay() 1650 | } 1651 | 1652 | // FirstOfMonth returns the first occurrence of a given day of the week in the current month 1653 | func (c *Carbon) FirstOfMonth(wd time.Weekday) *Carbon { 1654 | d := c.StartOfMonth() 1655 | if d.Weekday() != wd { 1656 | return d.Next(wd) 1657 | } 1658 | 1659 | return d 1660 | } 1661 | 1662 | // LastOfMonth returns the last occurrence of a given day of the week in the current month 1663 | func (c *Carbon) LastOfMonth(wd time.Weekday) *Carbon { 1664 | d := c.EndOfMonth() 1665 | if d.Weekday() != wd { 1666 | return d.Previous(wd) 1667 | } 1668 | 1669 | return d.StartOfDay() 1670 | } 1671 | 1672 | // LastDayOfMonth returns a new carbon instance with the last day of current month 1673 | func (c *Carbon) LastDayOfMonth() *Carbon { 1674 | return NewCarbon(time.Date(c.Year(), c.Month(), c.DaysInMonth(), 0, 0, 0, 0, time.UTC)) 1675 | } 1676 | 1677 | // FirstDayOfMonth returns a new carbon instance with the first day of current month 1678 | func (c *Carbon) FirstDayOfMonth() *Carbon { 1679 | return NewCarbon(time.Date(c.Year(), c.Month(), 1, 0, 0, 0, 0, time.UTC)) 1680 | } 1681 | 1682 | // NthOfMonth returns the given occurrence of a given day of the week in the current month 1683 | // If the calculated occurrence is outside the scope of current month, no modifications are made 1684 | func (c *Carbon) NthOfMonth(nth int, wd time.Weekday) *Carbon { 1685 | cp := c.Copy().StartOfMonth() 1686 | i := 0 1687 | if cp.Weekday() == wd { 1688 | i++ 1689 | } 1690 | for i < nth { 1691 | cp = cp.Next(wd) 1692 | i++ 1693 | } 1694 | if cp.Gt(c.EndOfMonth()) { 1695 | return c 1696 | } 1697 | 1698 | return cp 1699 | } 1700 | 1701 | // FirstOfQuarter returns the first occurrence of a given day of the week in the current quarter 1702 | func (c *Carbon) FirstOfQuarter(wd time.Weekday) *Carbon { 1703 | d := c.StartOfQuarter() 1704 | if d.Weekday() != wd { 1705 | return d.Next(wd) 1706 | } 1707 | 1708 | return d 1709 | } 1710 | 1711 | // LastOfQuarter returns the last occurrence of a given day of the week in the current quarter 1712 | func (c *Carbon) LastOfQuarter(wd time.Weekday) *Carbon { 1713 | d := c.EndOfQuarter() 1714 | if d.Weekday() != wd { 1715 | return d.Previous(wd) 1716 | } 1717 | 1718 | return d.StartOfDay() 1719 | } 1720 | 1721 | // NthOfQuarter returns the given occurrence of a given day of the week in the current quarter 1722 | // If the calculated occurrence is outside the scope of current quarter, no modifications are made 1723 | func (c *Carbon) NthOfQuarter(nth int, wd time.Weekday) *Carbon { 1724 | cp := c.Copy().StartOfQuarter() 1725 | i := 0 1726 | if cp.Weekday() == wd { 1727 | i++ 1728 | } 1729 | for i < nth { 1730 | cp = cp.Next(wd) 1731 | i++ 1732 | } 1733 | if cp.Gt(c.EndOfQuarter()) { 1734 | return c 1735 | } 1736 | 1737 | return cp 1738 | } 1739 | 1740 | // FirstOfYear returns the first occurrence of a given day of the week in the current year 1741 | func (c *Carbon) FirstOfYear(wd time.Weekday) *Carbon { 1742 | d := c.StartOfYear() 1743 | if d.Weekday() != wd { 1744 | return d.Next(wd) 1745 | } 1746 | 1747 | return d 1748 | } 1749 | 1750 | // LastOfYear returns the last occurrence of a given day of the week in the current year 1751 | func (c *Carbon) LastOfYear(wd time.Weekday) *Carbon { 1752 | d := c.EndOfYear() 1753 | if d.Weekday() != wd { 1754 | return d.Previous(wd) 1755 | } 1756 | 1757 | return d.StartOfDay() 1758 | } 1759 | 1760 | // NthOfYear returns the given occurrence of a given day of the week in the current year 1761 | // If the calculated occurrence is outside the scope of current year, no modifications are made 1762 | func (c *Carbon) NthOfYear(nth int, wd time.Weekday) *Carbon { 1763 | cp := c.Copy().StartOfYear() 1764 | i := 0 1765 | if cp.Weekday() == wd { 1766 | i++ 1767 | } 1768 | for i < nth { 1769 | cp = cp.Next(wd) 1770 | i++ 1771 | } 1772 | if cp.Gt(c.EndOfYear()) { 1773 | return c 1774 | } 1775 | 1776 | return cp 1777 | } 1778 | 1779 | // Average returns the average between a given carbon date and the current date 1780 | func (c *Carbon) Average(carb *Carbon) *Carbon { 1781 | if carb == nil { 1782 | carb = nowIn(c.Location()) 1783 | } 1784 | if c.Eq(carb) { 1785 | return c.Copy() 1786 | } 1787 | average := int(c.DiffInSeconds(carb, false) / 2) 1788 | 1789 | return c.AddSeconds(average) 1790 | } 1791 | 1792 | // Localization 1793 | 1794 | // GetTranslator returns Translator inside a Carbon instance if exist, 1795 | // otherwise it creates a new Translator with "en" as default locale 1796 | func (c *Carbon) GetTranslator() (*Translator, error) { 1797 | if c.Translator == nil { 1798 | c.Translator = translator() 1799 | } 1800 | 1801 | return c.Translator, nil 1802 | } 1803 | 1804 | func translator() *Translator { 1805 | t := NewTranslator() 1806 | t.SetLocale("en") 1807 | 1808 | return t 1809 | } 1810 | 1811 | // SetTranslator sets the Translator inside a Carbon instance 1812 | func (c *Carbon) SetTranslator(t *Translator) { 1813 | c.Translator = t 1814 | } 1815 | 1816 | // GetLocale returns locale of the Translator of Carbon 1817 | func (c *Carbon) GetLocale() string { 1818 | return c.Translator.GetLocale() 1819 | } 1820 | 1821 | // SetLocale sets locale for the Translator of Carbon 1822 | func (c *Carbon) SetLocale(l string) error { 1823 | err := c.Translator.SetLocale(l) 1824 | if err != nil { 1825 | return err 1826 | } 1827 | 1828 | return nil 1829 | } 1830 | 1831 | /* TODO 1832 | // String Formatting 1833 | 1834 | // FormatLocalized will format the carbon instance with the current locale 1835 | func (c *Carbon) FormatLocalized(format string) (string, error) { 1836 | if runtime.GOOS == "windows" { 1837 | regExpObj, err := regexp.Compile("#(?= sleepDuration.Seconds()) 35 | assert.Equal(t, frozenNowBefore, frozenNowAfter) 36 | assert.Equal(t, expectedTimeStamp, frozenNowBefore.Unix()) 37 | assert.Equal(t, expectedTimeStamp, frozenNowAfter.Unix()) 38 | 39 | carbon.Sleep(sleepDuration) 40 | 41 | frozenAfterSleep := carbon.Now() 42 | assert.NotEqual(t, frozenNowAfter, frozenAfterSleep) 43 | assert.Equal(t, expectedFrozenSleepTimeStamp, frozenAfterSleep.Unix()) 44 | } 45 | 46 | func TestUnFreeze(t *testing.T) { 47 | sleepDuration := 1 * time.Second 48 | 49 | // 2017-03-08T01:24:34+00:00 50 | expectedTimeStamp := int64(1488936274) 51 | 52 | timeToFreeze, err := carbon.CreateFromTimestampUTC(expectedTimeStamp) 53 | assert.Nil(t, err) 54 | 55 | carbon.Freeze(timeToFreeze.Time) 56 | defer carbon.UnFreeze() 57 | 58 | frozenNow := carbon.Now() 59 | 60 | // Really sleep 61 | time.Sleep(sleepDuration) 62 | 63 | carbon.UnFreeze() 64 | 65 | realNow := time.Now() 66 | unfrozenNow := carbon.Now() 67 | 68 | assert.NotEqual(t, frozenNow, unfrozenNow) 69 | assert.Equal(t, expectedTimeStamp, frozenNow.Unix()) 70 | assert.Equal(t, realNow.Unix(), unfrozenNow.Time.Unix()) 71 | } 72 | 73 | func TestNotSharing(t *testing.T) { 74 | // 2017-03-08T01:24:34+00:00 75 | expectedTimeStamp1 := int64(1488936274) 76 | timeToFreeze1, _ := carbon.CreateFromTimestampUTC(expectedTimeStamp1) 77 | carbon.Freeze(timeToFreeze1.Time) 78 | 79 | carbon1 := carbon.Now() 80 | 81 | time.Sleep(2 * time.Second) 82 | 83 | carbon11 := carbon.Now() 84 | 85 | // 2017-03-09T10:12:01+00:00 86 | expectedTimeStamp2 := int64(1489054321) 87 | timeToFreeze2, _ := carbon.CreateFromTimestampUTC(expectedTimeStamp2) 88 | carbon.Freeze(timeToFreeze2.Time) 89 | 90 | carbon2 := carbon.Now() 91 | 92 | assert.NotEqual(t, carbon1.UnixNano(), carbon2.UnixNano()) 93 | assert.Equal(t, carbon1.UnixNano(), carbon11.UnixNano()) 94 | assert.Equal(t, expectedTimeStamp1, carbon1.Unix()) 95 | assert.Equal(t, expectedTimeStamp1, carbon11.Unix()) 96 | assert.Equal(t, expectedTimeStamp2, carbon2.Unix()) 97 | } 98 | -------------------------------------------------------------------------------- /carboninterval.go: -------------------------------------------------------------------------------- 1 | package carbon 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // CarbonInterval represents an interval between two carbons. 8 | type CarbonInterval struct { 9 | Start *Carbon 10 | End *Carbon 11 | } 12 | 13 | // NewCarbonInterval returns a pointer to a new CarbonInterval instance 14 | func NewCarbonInterval(start, end *Carbon) (*CarbonInterval, error) { 15 | if start == nil { 16 | return nil, errors.New("start date cannot be nil") 17 | } 18 | if end == nil { 19 | return nil, errors.New("end date cannot be nil") 20 | } 21 | 22 | if start.Gte(end) { 23 | return nil, errors.New("the end date must be greater than or equal to the start date") 24 | } 25 | 26 | return &CarbonInterval{ 27 | Start: start, 28 | End: end, 29 | }, nil 30 | } 31 | 32 | // DiffInHours return the difference in hours between start and end date 33 | func (ci *CarbonInterval) DiffInHours() int64 { 34 | return ci.End.DiffInHours(ci.Start, true) 35 | } 36 | -------------------------------------------------------------------------------- /carboninterval_test.go: -------------------------------------------------------------------------------- 1 | package carbon 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestErrorOnConstruction(t *testing.T) { 11 | startDate, _ := Create(2009, time.November, 10, 23, 0, 0, 0, "UTC") 12 | endDate, _ := Create(2009, time.November, 9, 23, 0, 0, 0, "UTC") 13 | 14 | _, err := NewCarbonInterval(startDate, endDate) 15 | assert.Error(t, err, "the end date must be greater than or equal to the start date") 16 | } 17 | 18 | func TestDiffInHours(t *testing.T) { 19 | startDate, _ := Create(2009, time.November, 10, 23, 0, 0, 0, "UTC") 20 | endDate, _ := Create(2009, time.November, 10, 24, 0, 0, 0, "UTC") 21 | 22 | interval, _ := NewCarbonInterval(startDate, endDate) 23 | assert.Equal(t, int64(1), interval.DiffInHours()) 24 | } 25 | 26 | func TestErrorOnNilStartDate(t *testing.T) { 27 | endDate, _ := Create(2009, time.November, 10, 24, 0, 0, 0, "UTC") 28 | 29 | _, err := NewCarbonInterval(nil, endDate) 30 | assert.Error(t, err, "start date cannot be nil") 31 | } 32 | 33 | func TestErrorOnNilEndDate(t *testing.T) { 34 | startDate, _ := Create(2009, time.November, 10, 23, 0, 0, 0, "UTC") 35 | 36 | _, err := NewCarbonInterval(startDate, nil) 37 | assert.Error(t, err, "end date cannot be nil") 38 | } 39 | 40 | func TestErrorOnNilDates(t *testing.T) { 41 | _, err := NewCarbonInterval(nil, nil) 42 | assert.Error(t, err, "start date cannot be nil") 43 | } 44 | -------------------------------------------------------------------------------- /diff_test.go: -------------------------------------------------------------------------------- 1 | package carbon 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | // Check https://github.com/uniplaces/carbon/issues/30 11 | func TestCarbonDiffInYears(t *testing.T) { 12 | dob, _ := CreateFromDate(2000, time.June, 27, time.UTC.String()) 13 | 14 | yesterday, _ := CreateFromDate(2016, time.June, 26, time.UTC.String()) 15 | today, _ := CreateFromDate(2016, time.June, 27, time.UTC.String()) 16 | tomorrow, _ := CreateFromDate(2016, time.June, 28, time.UTC.String()) 17 | 18 | // Day before 16th birthday... Should be 15 19 | assert.Equal(t, int64(15), dob.DiffInYears(yesterday, true)) 20 | // Day of 16th birthday 21 | assert.Equal(t, int64(16), dob.DiffInYears(today, true)) 22 | // Day after 16th birthday 23 | assert.Equal(t, int64(16), dob.DiffInYears(tomorrow, true)) 24 | } 25 | 26 | func TestDiffForHumansNowAndSecond(t *testing.T) { 27 | gotTime, err := Now().DiffForHumans(nil, false, false, false) 28 | assert.Nil(t, err) 29 | assert.Equal(t, "1 second ago", gotTime) 30 | } 31 | 32 | func TestDiffForHumansNowAndSecondWithTimeZone(t *testing.T) { 33 | vanNow, err := NowInLocation("America/Vancouver") 34 | assert.Nil(t, err) 35 | 36 | hereNow := vanNow.Copy() 37 | err = hereNow.SetTimeZone(Now().TimeZone()) 38 | assert.Nil(t, err) 39 | 40 | gotTime, err := vanNow.DiffForHumans(nil, false, false, false) 41 | assert.Nil(t, err) 42 | assert.Equal(t, "1 second ago", gotTime) 43 | } 44 | 45 | func TestDiffForHumansNowAndSeconds(t *testing.T) { 46 | gotTime, err := Now().SubSeconds(2).DiffForHumans(nil, false, false, false) 47 | assert.Nil(t, err) 48 | assert.Equal(t, "2 seconds ago", gotTime) 49 | } 50 | 51 | func TestDiffForHumansNowAndNearlyMinute(t *testing.T) { 52 | gotTime, err := Now().SubSeconds(59).DiffForHumans(nil, false, false, false) 53 | assert.Nil(t, err) 54 | assert.Equal(t, "59 seconds ago", gotTime) 55 | } 56 | 57 | func TestDiffForHumansNowAndMinute(t *testing.T) { 58 | gotTime, err := Now().SubMinute().DiffForHumans(nil, false, false, false) 59 | assert.Nil(t, err) 60 | assert.Equal(t, "1 minute ago", gotTime) 61 | } 62 | 63 | func TestDiffForHumansNowAndMinutes(t *testing.T) { 64 | gotTime, err := Now().SubMinutes(2).DiffForHumans(nil, false, false, false) 65 | assert.Nil(t, err) 66 | assert.Equal(t, "2 minutes ago", gotTime) 67 | } 68 | 69 | func TestDiffForHumansNowAndNearlyHour(t *testing.T) { 70 | gotTime, err := Now().SubMinutes(59).DiffForHumans(nil, false, false, false) 71 | assert.Nil(t, err) 72 | assert.Equal(t, "59 minutes ago", gotTime) 73 | } 74 | 75 | func TestDiffForHumansNowAndHour(t *testing.T) { 76 | gotTime, err := Now().SubHour().DiffForHumans(nil, false, false, false) 77 | assert.Nil(t, err) 78 | assert.Equal(t, "1 hour ago", gotTime) 79 | } 80 | 81 | func TestDiffForHumansNowAndHours(t *testing.T) { 82 | gotTime, err := Now().SubHours(2).DiffForHumans(nil, false, false, false) 83 | assert.Nil(t, err) 84 | assert.Equal(t, "2 hours ago", gotTime) 85 | } 86 | 87 | func TestDiffForHumansNowAndNearlyDayOne(t *testing.T) { 88 | gotTime, err := Now().SubWeeks(4).DiffForHumans(nil, false, false, false) 89 | assert.Nil(t, err) 90 | assert.Equal(t, "4 weeks ago", gotTime) 91 | } 92 | 93 | func TestDiffForHumansNowAndNearlyDayTwo(t *testing.T) { 94 | gotTime, err := Now().SubHours(744).DiffForHumans(nil, false, false, false) 95 | assert.Nil(t, err) 96 | assert.Equal(t, "1 month ago", gotTime) 97 | } 98 | 99 | func TestDiffForHumansNowAndNearlyDayThree(t *testing.T) { 100 | gotTime, err := Now().SubHours(745).DiffForHumans(nil, false, false, false) 101 | assert.Nil(t, err) 102 | assert.Equal(t, "1 month ago", gotTime) 103 | } 104 | 105 | func TestDiffForHumansNowAndLessThanDay(t *testing.T) { 106 | gotTime, err := Now().SubHours(23).DiffForHumans(nil, false, false, false) 107 | assert.Nil(t, err) 108 | assert.Equal(t, "23 hours ago", gotTime) 109 | } 110 | 111 | func TestDiffForHumansNowAndDay(t *testing.T) { 112 | gotTime, err := Now().SubDay().DiffForHumans(nil, false, false, false) 113 | assert.Nil(t, err) 114 | assert.Equal(t, "1 day ago", gotTime) 115 | } 116 | 117 | func TestDiffForHumansNowAndDays(t *testing.T) { 118 | gotTime, err := Now().SubDays(2).DiffForHumans(nil, false, false, false) 119 | assert.Nil(t, err) 120 | assert.Equal(t, "2 days ago", gotTime) 121 | } 122 | 123 | func TestDiffForHumansNowAndNearlyWeek(t *testing.T) { 124 | gotTime, err := Now().SubDays(6).DiffForHumans(nil, false, false, false) 125 | assert.Nil(t, err) 126 | assert.Equal(t, "6 days ago", gotTime) 127 | } 128 | 129 | func TestDiffForHumansNowAndWeek(t *testing.T) { 130 | gotTime, err := Now().SubWeek().DiffForHumans(nil, false, false, false) 131 | assert.Nil(t, err) 132 | assert.Equal(t, "1 week ago", gotTime) 133 | } 134 | 135 | func TestDiffForHumansNowAndWeeks(t *testing.T) { 136 | gotTime, err := Now().SubWeeks(2).DiffForHumans(nil, false, false, false) 137 | assert.Nil(t, err) 138 | assert.Equal(t, "2 weeks ago", gotTime) 139 | } 140 | 141 | func TestDiffForHumansNowAndNearlyMonth(t *testing.T) { 142 | gotTime, err := Now().SubWeeks(3).DiffForHumans(nil, false, false, false) 143 | assert.Nil(t, err) 144 | assert.Equal(t, "3 weeks ago", gotTime) 145 | } 146 | 147 | func TestDiffForHumansNowAndMonth(t *testing.T) { 148 | gotTime, err := Now().SubMonth().DiffForHumans(nil, false, false, false) 149 | assert.Nil(t, err) 150 | assert.Equal(t, "1 month ago", gotTime) 151 | } 152 | 153 | func TestDiffForHumansNowAndMonths(t *testing.T) { 154 | gotTime, err := Now().SubMonths(2).DiffForHumans(nil, false, false, false) 155 | assert.Nil(t, err) 156 | assert.Equal(t, "2 months ago", gotTime) 157 | } 158 | 159 | //func TestDiffForHumansNowAndNearlyYear(t *testing.T) { 160 | // gotTime, err := Now().SubMonths(11).DiffForHumans(nil, false, false, false) 161 | // assert.Nil(t, err) 162 | // assert.Equal(t, "11 months ago", gotTime) 163 | //} 164 | 165 | func TestDiffForHumansNowAndYear(t *testing.T) { 166 | gotTime, err := Now().SubYear().DiffForHumans(nil, false, false, false) 167 | assert.Nil(t, err) 168 | assert.Equal(t, "1 year ago", gotTime) 169 | } 170 | 171 | func TestDiffForHumansNowAndYears(t *testing.T) { 172 | gotTime, err := Now().SubYears(2).DiffForHumans(nil, false, false, false) 173 | assert.Nil(t, err) 174 | assert.Equal(t, "2 years ago", gotTime) 175 | } 176 | 177 | func TestDiffForHumansNowAndFutureSecond(t *testing.T) { 178 | gotTime, err := Now().AddSecond().DiffForHumans(nil, false, false, false) 179 | assert.Nil(t, err) 180 | assert.Equal(t, "1 second from now", gotTime) 181 | } 182 | 183 | func TestDiffForHumansNowAndFutureSeconds(t *testing.T) { 184 | gotTime, err := Now().AddSeconds(2).DiffForHumans(nil, true, false, false) 185 | assert.Nil(t, err) 186 | assert.Equal(t, "2 seconds from now", gotTime) 187 | } 188 | 189 | func TestDiffForHumansNowAndNearlyFutureMinute(t *testing.T) { 190 | gotTime, err := Now().AddSeconds(59).DiffForHumans(nil, true, false, false) 191 | assert.Nil(t, err) 192 | assert.Equal(t, "59 seconds from now", gotTime) 193 | } 194 | 195 | func TestDiffForHumansNowAndFutureMinute(t *testing.T) { 196 | gotTime, err := Now().AddMinute().DiffForHumans(nil, true, false, false) 197 | assert.Nil(t, err) 198 | assert.Equal(t, "1 minute from now", gotTime) 199 | } 200 | 201 | func TestDiffForHumansNowAndFutureMinutes(t *testing.T) { 202 | gotTime, err := Now().AddMinutes(2).DiffForHumans(nil, true, false, false) 203 | assert.Nil(t, err) 204 | assert.Equal(t, "2 minutes from now", gotTime) 205 | } 206 | 207 | func TestDiffForHumansNowAndNearlyFutureHour(t *testing.T) { 208 | gotTime, err := Now().AddMinutes(59).DiffForHumans(nil, true, false, false) 209 | assert.Nil(t, err) 210 | assert.Equal(t, "59 minutes from now", gotTime) 211 | } 212 | 213 | func TestDiffForHumansNowAndFutureHour(t *testing.T) { 214 | gotTime, err := Now().AddHour().DiffForHumans(nil, true, false, false) 215 | assert.Nil(t, err) 216 | assert.Equal(t, "1 hour from now", gotTime) 217 | } 218 | 219 | func TestDiffForHumansNowAndFutureHours(t *testing.T) { 220 | gotTime, err := Now().AddHours(2).DiffForHumans(nil, true, false, false) 221 | assert.Nil(t, err) 222 | assert.Equal(t, "2 hours from now", gotTime) 223 | } 224 | 225 | func TestDiffForHumansNowAndNearlyFutureDay(t *testing.T) { 226 | gotTime, err := Now().AddHours(23).DiffForHumans(nil, true, false, false) 227 | assert.Nil(t, err) 228 | assert.Equal(t, "23 hours from now", gotTime) 229 | } 230 | 231 | func TestDiffForHumansNowAndFutureDay(t *testing.T) { 232 | gotTime, err := Now().AddDay().DiffForHumans(nil, true, false, false) 233 | assert.Nil(t, err) 234 | assert.Equal(t, "1 day from now", gotTime) 235 | } 236 | 237 | func TestDiffForHumansNowAndFutureDays(t *testing.T) { 238 | gotTime, err := Now().AddDays(2).DiffForHumans(nil, true, false, false) 239 | assert.Nil(t, err) 240 | assert.Equal(t, "2 days from now", gotTime) 241 | } 242 | 243 | func TestDiffForHumansNowAndNearlyFutureWeek(t *testing.T) { 244 | gotTime, err := Now().AddDays(6).DiffForHumans(nil, true, false, false) 245 | assert.Nil(t, err) 246 | assert.Equal(t, "6 days from now", gotTime) 247 | } 248 | 249 | func TestDiffForHumansNowAndFutureWeek(t *testing.T) { 250 | gotTime, err := Now().AddWeek().DiffForHumans(nil, true, false, false) 251 | assert.Nil(t, err) 252 | assert.Equal(t, "1 week from now", gotTime) 253 | } 254 | 255 | func TestDiffForHumansNowAndFutureWeeks(t *testing.T) { 256 | gotTime, err := Now().AddWeeks(2).DiffForHumans(nil, true, false, false) 257 | assert.Nil(t, err) 258 | assert.Equal(t, "2 weeks from now", gotTime) 259 | } 260 | 261 | func TestDiffForHumansNowAndNearlyFutureMonth(t *testing.T) { 262 | gotTime, err := Now().AddWeeks(3).DiffForHumans(nil, true, false, false) 263 | assert.Nil(t, err) 264 | assert.Equal(t, "3 weeks from now", gotTime) 265 | } 266 | 267 | func TestDiffForHumansNowAndLessThanFutureMonth(t *testing.T) { 268 | gotTime, err := Now().AddWeeks(4).DiffForHumans(nil, true, false, false) 269 | assert.Nil(t, err) 270 | assert.Equal(t, "4 weeks from now", gotTime) 271 | } 272 | 273 | //func TestDiffForHumansNowAndFutureMonth(t *testing.T) { 274 | // gotTime, err := Now().AddMonth().DiffForHumans(nil, true, false, false) 275 | // assert.Nil(t, err) 276 | // assert.Equal(t, "1 month from now", gotTime) 277 | //} 278 | 279 | func TestDiffForHumansNowAndFutureMonths(t *testing.T) { 280 | gotTime, err := Now().AddMonths(2).DiffForHumans(nil, true, false, false) 281 | assert.Nil(t, err) 282 | assert.Equal(t, "2 months from now", gotTime) 283 | } 284 | 285 | func TestDiffForHumansNowAndNearlyFutureYear(t *testing.T) { 286 | gotTime, err := Now().AddMonths(11).DiffForHumans(nil, true, false, false) 287 | assert.Nil(t, err) 288 | assert.Equal(t, "11 months from now", gotTime) 289 | } 290 | 291 | func TestDiffForHumansNowAndFutureYear(t *testing.T) { 292 | gotTime, err := Now().AddYear().DiffForHumans(nil, true, false, false) 293 | assert.Nil(t, err) 294 | assert.Equal(t, "1 year from now", gotTime) 295 | } 296 | 297 | func TestDiffForHumansNowAndFutureYears(t *testing.T) { 298 | gotTime, err := Now().AddYears(2).DiffForHumans(nil, true, false, false) 299 | assert.Nil(t, err) 300 | assert.Equal(t, "2 years from now", gotTime) 301 | } 302 | 303 | func TestDiffForHumansOtherAndSecond(t *testing.T) { 304 | gotTime, err := Now().DiffForHumans(Now().AddSecond(), false, false, false) 305 | assert.Nil(t, err) 306 | assert.Equal(t, "1 second before", gotTime) 307 | } 308 | 309 | func TestDiffForHumansOtherAndSeconds(t *testing.T) { 310 | gotTime, err := Now().DiffForHumans(Now().AddSeconds(2), false, false, false) 311 | assert.Nil(t, err) 312 | assert.Equal(t, "2 seconds before", gotTime) 313 | } 314 | 315 | func TestDiffForHumansOtherAndNearlyMinute(t *testing.T) { 316 | gotTime, err := Now().DiffForHumans(Now().AddSeconds(59), false, false, false) 317 | assert.Nil(t, err) 318 | assert.Equal(t, "59 seconds before", gotTime) 319 | } 320 | 321 | func TestDiffForHumansOtherAndMinute(t *testing.T) { 322 | gotTime, err := Now().DiffForHumans(Now().AddMinute(), false, false, false) 323 | assert.Nil(t, err) 324 | assert.Equal(t, "1 minute before", gotTime) 325 | } 326 | 327 | func TestDiffForHumansOtherAndMinutes(t *testing.T) { 328 | gotTime, err := Now().DiffForHumans(Now().AddMinutes(2), false, false, false) 329 | assert.Nil(t, err) 330 | assert.Equal(t, "2 minutes before", gotTime) 331 | } 332 | 333 | func TestDiffForHumansOtherAndNearlyHour(t *testing.T) { 334 | gotTime, err := Now().DiffForHumans(Now().AddMinutes(59), false, false, false) 335 | assert.Nil(t, err) 336 | assert.Equal(t, "59 minutes before", gotTime) 337 | } 338 | 339 | func TestDiffForHumansOtherAndHour(t *testing.T) { 340 | gotTime, err := Now().DiffForHumans(Now().AddHour(), false, false, false) 341 | assert.Nil(t, err) 342 | assert.Equal(t, "1 hour before", gotTime) 343 | } 344 | 345 | func TestDiffForHumansOtherAndHours(t *testing.T) { 346 | gotTime, err := Now().DiffForHumans(Now().AddHours(2), false, false, false) 347 | assert.Nil(t, err) 348 | assert.Equal(t, "2 hours before", gotTime) 349 | } 350 | 351 | func TestDiffForHumansOtherAndNearlyDay(t *testing.T) { 352 | gotTime, err := Now().DiffForHumans(Now().AddHours(23), false, false, false) 353 | assert.Nil(t, err) 354 | assert.Equal(t, "23 hours before", gotTime) 355 | } 356 | 357 | func TestDiffForHumansOtherAndDay(t *testing.T) { 358 | gotTime, err := Now().DiffForHumans(Now().AddDay(), false, false, false) 359 | assert.Nil(t, err) 360 | assert.Equal(t, "1 day before", gotTime) 361 | } 362 | 363 | func TestDiffForHumansOtherAndDays(t *testing.T) { 364 | gotTime, err := Now().DiffForHumans(Now().AddDays(2), false, false, false) 365 | assert.Nil(t, err) 366 | assert.Equal(t, "2 days before", gotTime) 367 | } 368 | 369 | func TestDiffForHumansOtherAndNearlyWeek(t *testing.T) { 370 | gotTime, err := Now().DiffForHumans(Now().AddDays(6), false, false, false) 371 | assert.Nil(t, err) 372 | assert.Equal(t, "6 days before", gotTime) 373 | } 374 | 375 | func TestDiffForHumansOtherAndWeek(t *testing.T) { 376 | gotTime, err := Now().DiffForHumans(Now().AddWeek(), false, false, false) 377 | assert.Nil(t, err) 378 | assert.Equal(t, "1 week before", gotTime) 379 | } 380 | 381 | func TestDiffForHumansOtherAndWeeks(t *testing.T) { 382 | gotTime, err := Now().DiffForHumans(Now().AddWeeks(2), false, false, false) 383 | assert.Nil(t, err) 384 | assert.Equal(t, "2 weeks before", gotTime) 385 | } 386 | 387 | func TestDiffForHumansOtherAndNearlyMonth(t *testing.T) { 388 | gotTime, err := Now().DiffForHumans(Now().AddWeeks(3), false, false, false) 389 | assert.Nil(t, err) 390 | assert.Equal(t, "3 weeks before", gotTime) 391 | } 392 | 393 | func TestDiffForHumansOtherAndLessThanMonth(t *testing.T) { 394 | gotTime, err := Now().DiffForHumans(Now().AddWeeks(4), false, false, false) 395 | assert.Nil(t, err) 396 | assert.Equal(t, "4 weeks before", gotTime) 397 | } 398 | 399 | func TestDiffForHumansOtherAndMonth(t *testing.T) { 400 | gotTime, err := Now().DiffForHumans(Now().AddMonth(), false, false, false) 401 | assert.Nil(t, err) 402 | assert.Equal(t, "1 month before", gotTime) 403 | } 404 | 405 | func TestDiffForHumansOtherAndMonths(t *testing.T) { 406 | gotTime, err := Now().DiffForHumans(Now().AddMonths(2), false, false, false) 407 | assert.Nil(t, err) 408 | assert.Equal(t, "2 months before", gotTime) 409 | } 410 | 411 | func TestDiffForHumansOtherAndNearlyYear(t *testing.T) { 412 | gotTime, err := Now().DiffForHumans(Now().AddMonths(11), false, false, false) 413 | assert.Nil(t, err) 414 | assert.Equal(t, "11 months before", gotTime) 415 | } 416 | 417 | //func TestDiffForHumansOtherAndYear(t *testing.T) { 418 | // gotTime, err := Now().DiffForHumans(Now().AddYear(), false, false, false) 419 | // assert.Nil(t, err) 420 | // assert.Equal(t, "1 year before", gotTime) 421 | //} 422 | 423 | func TestDiffForHumansOtherAndYears(t *testing.T) { 424 | gotTime, err := Now().DiffForHumans(Now().AddYears(2), false, false, false) 425 | assert.Nil(t, err) 426 | assert.Equal(t, "2 years before", gotTime) 427 | } 428 | 429 | func TestDiffForHumansOtherAndFutureSecond(t *testing.T) { 430 | gotTime, err := Now().DiffForHumans(Now().SubSecond(), false, false, false) 431 | assert.Nil(t, err) 432 | assert.Equal(t, "1 second after", gotTime) 433 | } 434 | 435 | func TestDiffForHumansOtherAndFutureSeconds(t *testing.T) { 436 | gotTime, err := Now().DiffForHumans(Now().SubSeconds(2), true, false, false) 437 | assert.Nil(t, err) 438 | assert.Equal(t, "2 seconds after", gotTime) 439 | } 440 | 441 | func TestDiffForHumansOtherAndNearlyFutureMinute(t *testing.T) { 442 | gotTime, err := Now().DiffForHumans(Now().SubSeconds(59), true, false, false) 443 | assert.Nil(t, err) 444 | assert.Equal(t, "59 seconds after", gotTime) 445 | } 446 | 447 | func TestDiffForHumansOtherAndFutureMinute(t *testing.T) { 448 | gotTime, err := Now().DiffForHumans(Now().SubMinute(), true, false, false) 449 | assert.Nil(t, err) 450 | assert.Equal(t, "1 minute after", gotTime) 451 | } 452 | 453 | func TestDiffForHumansOtherAndFutureMinutes(t *testing.T) { 454 | gotTime, err := Now().DiffForHumans(Now().SubMinutes(2), true, false, false) 455 | assert.Nil(t, err) 456 | assert.Equal(t, "2 minutes after", gotTime) 457 | } 458 | 459 | func TestDiffForHumansOtherAndNearlyFutureHour(t *testing.T) { 460 | gotTime, err := Now().DiffForHumans(Now().SubMinutes(59), true, false, false) 461 | assert.Nil(t, err) 462 | assert.Equal(t, "59 minutes after", gotTime) 463 | } 464 | 465 | func TestDiffForHumansOtherAndFutureHour(t *testing.T) { 466 | gotTime, err := Now().DiffForHumans(Now().SubHour(), true, false, false) 467 | assert.Nil(t, err) 468 | assert.Equal(t, "1 hour after", gotTime) 469 | } 470 | 471 | func TestDiffForHumansOtherAndFutureHours(t *testing.T) { 472 | gotTime, err := Now().DiffForHumans(Now().SubHours(2), true, false, false) 473 | assert.Nil(t, err) 474 | assert.Equal(t, "2 hours after", gotTime) 475 | } 476 | 477 | func TestDiffForHumansOtherAndNearlyFutureDay(t *testing.T) { 478 | gotTime, err := Now().DiffForHumans(Now().SubHours(23), true, false, false) 479 | assert.Nil(t, err) 480 | assert.Equal(t, "23 hours after", gotTime) 481 | } 482 | 483 | func TestDiffForHumansOtherAndFutureDay(t *testing.T) { 484 | gotTime, err := Now().DiffForHumans(Now().SubDay(), true, false, false) 485 | assert.Nil(t, err) 486 | assert.Equal(t, "1 day after", gotTime) 487 | } 488 | 489 | func TestDiffForHumansOtherAndFutureDays(t *testing.T) { 490 | gotTime, err := Now().DiffForHumans(Now().SubDays(2), true, false, false) 491 | assert.Nil(t, err) 492 | assert.Equal(t, "2 days after", gotTime) 493 | } 494 | 495 | func TestDiffForHumansOtherAndNearlyFutureWeek(t *testing.T) { 496 | gotTime, err := Now().DiffForHumans(Now().SubDays(6), true, false, false) 497 | assert.Nil(t, err) 498 | assert.Equal(t, "6 days after", gotTime) 499 | } 500 | 501 | func TestDiffForHumansOtherAndFutureWeek(t *testing.T) { 502 | gotTime, err := Now().DiffForHumans(Now().SubWeek(), true, false, false) 503 | assert.Nil(t, err) 504 | assert.Equal(t, "1 week after", gotTime) 505 | } 506 | 507 | func TestDiffForHumansOtherAndFutureWeeks(t *testing.T) { 508 | gotTime, err := Now().DiffForHumans(Now().SubWeeks(2), true, false, false) 509 | assert.Nil(t, err) 510 | assert.Equal(t, "2 weeks after", gotTime) 511 | } 512 | 513 | func TestDiffForHumansOtherAndNearlyFutureMonth(t *testing.T) { 514 | gotTime, err := Now().DiffForHumans(Now().SubWeeks(3), true, false, false) 515 | assert.Nil(t, err) 516 | assert.Equal(t, "3 weeks after", gotTime) 517 | } 518 | 519 | func TestDiffForHumansOtherAndLessThanFutureMonth(t *testing.T) { 520 | gotTime, err := Now().DiffForHumans(Now().SubWeeks(4), true, false, false) 521 | assert.Nil(t, err) 522 | assert.Equal(t, "4 weeks after", gotTime) 523 | } 524 | 525 | func TestDiffForHumansOtherAndFutureMonth(t *testing.T) { 526 | gotTime, err := Now().AddMonth().DiffForHumans(Now(), true, false, false) 527 | assert.Nil(t, err) 528 | assert.Equal(t, "1 month after", gotTime) 529 | } 530 | 531 | func TestDiffForHumansOtherAndFutureMonths(t *testing.T) { 532 | gotTime, err := Now().DiffForHumans(Now().SubMonths(2), true, false, false) 533 | assert.Nil(t, err) 534 | assert.Equal(t, "2 months after", gotTime) 535 | } 536 | 537 | //func TestDiffForHumansOtherAndNearlyFutureYear(t *testing.T) { 538 | // gotTime, err := Now().DiffForHumans(Now().SubMonths(11), true, false, false) 539 | // assert.Nil(t, err) 540 | // assert.Equal(t, "11 months after", gotTime) 541 | //} 542 | 543 | func TestDiffForHumansOtherAndFutureYear(t *testing.T) { 544 | gotTime, err := Now().DiffForHumans(Now().SubYear(), true, false, false) 545 | assert.Nil(t, err) 546 | assert.Equal(t, "1 year after", gotTime) 547 | } 548 | 549 | func TestDiffForHumansOtherAndFutureYears(t *testing.T) { 550 | gotTime, err := Now().DiffForHumans(Now().SubYears(2), true, false, false) 551 | assert.Nil(t, err) 552 | assert.Equal(t, "2 years after", gotTime) 553 | } 554 | 555 | func TestDiffForHumansAbsoluteSeconds(t *testing.T) { 556 | gotTime, err := Now().DiffForHumans(Now().SubSeconds(59), true, true, false) 557 | assert.Nil(t, err) 558 | assert.Equal(t, "59 seconds", gotTime) 559 | 560 | gotTime2, err := Now().DiffForHumans(Now().AddSeconds(59), true, true, false) 561 | assert.Nil(t, err) 562 | assert.Equal(t, "59 seconds", gotTime2) 563 | } 564 | 565 | func TestDiffForOneMinute(t *testing.T) { 566 | gotTime, err := Now().SubMinute().DiffForHumans(nil, false, false, false) 567 | assert.Nil(t, err) 568 | assert.Equal(t, "1 minute ago", gotTime) 569 | } 570 | 571 | func TestDiffForHumansAbsoluteMinutes(t *testing.T) { 572 | gotTime, err := Now().DiffForHumans(Now().SubMinutes(30), true, true, false) 573 | assert.Nil(t, err) 574 | assert.Equal(t, "30 minutes", gotTime) 575 | 576 | gotTime2, err := Now().DiffForHumans(Now().AddMinutes(30), true, true, false) 577 | assert.Nil(t, err) 578 | assert.Equal(t, "30 minutes", gotTime2) 579 | } 580 | 581 | func TestDiffForHumansAbsoluteHours(t *testing.T) { 582 | gotTime, err := Now().DiffForHumans(Now().SubHours(3), true, true, false) 583 | assert.Nil(t, err) 584 | assert.Equal(t, "3 hours", gotTime) 585 | 586 | gotTime2, err := Now().DiffForHumans(Now().AddHours(3), true, true, false) 587 | assert.Nil(t, err) 588 | assert.Equal(t, "3 hours", gotTime2) 589 | } 590 | 591 | func TestForDiffInHours(t *testing.T) { 592 | a := NewCarbon(time.Now()) 593 | b := NewCarbon(time.Now().Add(time.Hour * 10)) 594 | 595 | gotTime, err := a.DiffForHumans(b, false, false, false) 596 | 597 | assert.Nil(t, err) 598 | assert.Equal(t, "10 hours before", gotTime) 599 | } 600 | 601 | func TestDiffForHumansAbsoluteDays(t *testing.T) { 602 | gotTime, err := Now().DiffForHumans(Now().SubDays(2), true, true, false) 603 | assert.Nil(t, err) 604 | assert.Equal(t, "2 days", gotTime) 605 | 606 | gotTime2, err := Now().DiffForHumans(Now().AddDays(2), true, true, false) 607 | assert.Nil(t, err) 608 | assert.Equal(t, "2 days", gotTime2) 609 | } 610 | 611 | func TestDiffForHumansAbsoluteWeeks(t *testing.T) { 612 | gotTime, err := Now().DiffForHumans(Now().SubWeeks(2), true, true, false) 613 | assert.Nil(t, err) 614 | assert.Equal(t, "2 weeks", gotTime) 615 | 616 | gotTime2, err := Now().DiffForHumans(Now().AddWeeks(2), true, true, false) 617 | assert.Nil(t, err) 618 | assert.Equal(t, "2 weeks", gotTime2) 619 | } 620 | 621 | func TestDiffForHumansAbsoluteMonths(t *testing.T) { 622 | gotTime, err := Now().DiffForHumans(Now().SubMonths(2), true, true, false) 623 | assert.Nil(t, err) 624 | assert.Equal(t, "2 months", gotTime) 625 | 626 | gotTime2, err := Now().DiffForHumans(Now().AddMonths(2), true, true, false) 627 | assert.Nil(t, err) 628 | assert.Equal(t, "2 months", gotTime2) 629 | } 630 | -------------------------------------------------------------------------------- /examples/addsub.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/uniplaces/carbon" 7 | ) 8 | 9 | func addSub() { 10 | t1, _ := carbon.Create(2010, 1, 4, 19, 10, 10, 0, "UTC") 11 | 12 | t1 = t1.AddYear() // 2011-01-04 19:10:10 13 | t1 = t1.AddMonth() // 2011-02-04 19:10:10 14 | t1 = t1.SubDay() // 2011-02-03 19:10:10 15 | t1 = t1.SubYears(10) // 2001-02-03 19:10:10 16 | t1 = t1.AddMinutes(5) // 2001-02-03 19:15:10 17 | t1 = t1.AddWeekday() // 2001-02-05 19:15:10 18 | t1 = t1.SubHours(10) // 2001-02-05 10:15:10 19 | 20 | fmt.Println(t1) 21 | } 22 | -------------------------------------------------------------------------------- /examples/comparison.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/uniplaces/carbon" 7 | ) 8 | 9 | func comparison() { 10 | t1, _ := carbon.CreateFromDate(2010, 10, 1, "Europe/Paris") 11 | t2, _ := carbon.CreateFromDate(2011, 10, 20, "Europe/Paris") 12 | 13 | fmt.Printf("t1 equal to t2: %t", t1.Eq(t2)) 14 | fmt.Printf("t1 not equal to t2: %t", t1.Ne(t2)) 15 | 16 | fmt.Printf("t1 greater than t2: %t", t1.Gt(t2)) 17 | fmt.Printf("t1 less than t2: %t", t1.Lt(t2)) 18 | 19 | t3, _ := carbon.CreateFromDate(2011, 1, 20, "Europe/Paris") 20 | // The third parameter states that t3 could be equal to either t1 or t2 21 | fmt.Printf("t3 between t1 and t2: %t", t3.Between(t1, t2, true)) 22 | 23 | now := carbon.Now() 24 | fmt.Printf("Weekday? %t", now.IsWeekday()) 25 | fmt.Printf("Weekend? %t", now.IsWeekend()) 26 | fmt.Printf("LeapYear? %t", now.IsLeapYear()) 27 | fmt.Printf("Past? %t", now.IsPast()) 28 | fmt.Printf("Future? %t", now.IsFuture()) 29 | } 30 | -------------------------------------------------------------------------------- /examples/diff.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/uniplaces/carbon" 7 | ) 8 | 9 | func diff() { 10 | vancouver, _ := carbon.Today("America/Vancouver") 11 | london, _ := carbon.Today("Europe/London") 12 | fmt.Println(vancouver.DiffInSeconds(london, true)) // 0 13 | 14 | ottawa, _ := carbon.CreateFromDate(2000, 1, 1, "America/Toronto") 15 | vancouver, _ = carbon.CreateFromDate(2000, 1, 1, "America/Vancouver") 16 | fmt.Println(ottawa.DiffInHours(vancouver, true)) // 3 17 | 18 | fmt.Println(ottawa.DiffInHours(vancouver, false)) // 3 19 | fmt.Println(vancouver.DiffInHours(ottawa, false)) // -3 20 | 21 | t, _ := carbon.CreateFromDate(2012, 1, 31, "UTC") 22 | fmt.Println(t.DiffInDays(t.Copy().AddMonth(), true)) // 31 23 | fmt.Println(t.DiffInDays(t.Copy().SubMonth(), false)) // -31 24 | 25 | t, _ = carbon.CreateFromDate(2012, 4, 30, "UTC") 26 | fmt.Println(t.DiffInDays(t.Copy().AddMonth(), true)) // 30 27 | fmt.Println(t.DiffInDays(t.Copy().AddWeek(), true)) // 7 28 | 29 | t, _ = carbon.CreateFromTime(10, 1, 1, 0, "UTC") 30 | fmt.Println(t.DiffInMinutes(t.Copy().AddSeconds(59), true)) // 0 31 | fmt.Println(t.DiffInMinutes(t.Copy().AddSeconds(60), true)) // 1 32 | fmt.Println(t.DiffInMinutes(t.Copy().AddSeconds(119), true)) // 1 33 | fmt.Println(t.DiffInMinutes(t.Copy().AddSeconds(120), true)) // 2 34 | } 35 | -------------------------------------------------------------------------------- /examples/formats.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/uniplaces/carbon" 7 | ) 8 | 9 | func formats() { 10 | now := carbon.Now() 11 | 12 | fmt.Printf("Date in Atom String: %s\n", now.AtomString()) 13 | fmt.Printf("Date in Cookie String: %s\n", now.CookieString()) 14 | fmt.Printf("Date in ISO 8601 String: %s\n", now.ISO8601String()) 15 | fmt.Printf("Date in Rss String: %s\n", now.RSSString()) 16 | fmt.Printf("Date in W3C String: %s\n", now.W3CString()) 17 | } 18 | -------------------------------------------------------------------------------- /examples/instantiation.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/uniplaces/carbon" 8 | ) 9 | 10 | func instantiation() { 11 | now := carbon.NewCarbon(time.Now()) 12 | fmt.Printf("New carbon from time instance: %s\n", now) 13 | 14 | now = carbon.Now() 15 | fmt.Printf("New carbon from Now function: %s\n", now) 16 | 17 | fromDate, _ := carbon.CreateFromDate(2000, 1, 1, "Europe/London") 18 | fmt.Printf("Created from date: %s\n", fromDate) 19 | 20 | fromTime, _ := carbon.CreateFromTime(9, 16, 11, 0, "Europe/Madrid") 21 | fmt.Printf("Created from time: %s\n", fromTime) 22 | 23 | parsed, _ := carbon.Parse(carbon.DateFormat, "2000-08-20", "Europe/Berlin") 24 | fmt.Printf("Parsed time: %s\n", parsed) 25 | } 26 | -------------------------------------------------------------------------------- /examples/modifiers.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/uniplaces/carbon" 8 | ) 9 | 10 | func modifiers() { 11 | t1, _ := carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Lisbon/Rome") 12 | fmt.Printf("Start of day:%s\n", t1.StartOfDay()) // 2012-01-31 00:00:00 13 | 14 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 15 | fmt.Printf("End of day:%s\n", t1.EndOfDay()) // 2012-01-31 23:59:59 16 | 17 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 18 | fmt.Printf("Start of month:%s\n", t1.StartOfMonth()) // 2012-01-01 00:00:00 19 | 20 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 21 | fmt.Printf("End of month:%s\n", t1.EndOfMonth()) // 2012-01-31 23:59:59 22 | 23 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 24 | fmt.Printf("Start of year:%s\n", t1.StartOfYear()) // 2012-01-01 00:00:00 25 | 26 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 27 | fmt.Printf("End of year:%s\n", t1.EndOfYear()) // 2012-12-31 23:59:59 28 | 29 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 30 | fmt.Printf("Start of decade:%s\n", t1.StartOfDecade()) // 2010-01-01 00:00:00 31 | 32 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 33 | fmt.Printf("End of decade:%s\n", t1.EndOfDecade()) // 2019-12-31 23:59:59 34 | 35 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 36 | fmt.Printf("Start of century:%s\n", t1.StartOfCentury()) // 2000-01-01 00:00:00 37 | 38 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 39 | fmt.Printf("End of century:%s\n", t1.EndOfCentury()) // 2099-12-31 23:59:59 40 | 41 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 42 | fmt.Printf("Start of week:%s\n", t1.StartOfWeek()) // 2012-01-30 00:00:00 43 | 44 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 45 | fmt.Printf("End of week:%s\n", t1.EndOfWeek()) // 2012-02-05 23:59:59 46 | 47 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 48 | fmt.Printf("Next:%s\n", t1.Next(time.Wednesday)) // 2012-02-01 00:00:00 49 | 50 | t1, _ = carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Europe/Rome") 51 | fmt.Printf("Previous:%s\n", t1.Previous(time.Wednesday)) // 2012-01-25 00:00:00 52 | } 53 | -------------------------------------------------------------------------------- /examples/period.go: -------------------------------------------------------------------------------- 1 | package examples 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/uniplaces/carbon" 7 | ) 8 | 9 | func period() { 10 | t1, _ := carbon.Create(2012, 1, 1, 12, 0, 0, 0, "Lisbon/Rome") 11 | t2, _ := carbon.Create(2012, 1, 31, 12, 0, 0, 0, "Lisbon/Rome") 12 | days := 7 13 | 14 | periods, err := carbon.Period(t1, days, t2) 15 | if err != nil { 16 | return 17 | } 18 | 19 | for _, val := range periods { 20 | fmt.Println(val) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/uniplaces/carbon 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/davecgh/go-spew v1.1.0 // indirect 7 | github.com/pmezard/go-difflib v1.0.0 // indirect 8 | github.com/stretchr/testify v1.2.1 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/testify v1.2.1 h1:52QO5WkIUcHGIR7EnGagH88x1bUzqGXTC5/1bDTUQ7U= 6 | github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 7 | -------------------------------------------------------------------------------- /lang/af.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 jaar|:count jare", 3 | "y":"1 jaar|:count jare", 4 | "month":"1 maand|:count maande", 5 | "m":"1 maand|:count maande", 6 | "week":"1 week|:count weke", 7 | "w":"1 week|:count weke", 8 | "day":"1 dag|:count dae", 9 | "d":"1 dag|:count dae", 10 | "hour":"1 uur|:count ure", 11 | "h":"1 uur|:count ure", 12 | "minute":"1 minuut|:count minute", 13 | "min":"1 minuut|:count minute", 14 | "second":"1 sekond|:count sekondes", 15 | "s":"1 sekond|:count sekondes", 16 | "ago":":time terug", 17 | "from_now":":time van nou af", 18 | "after":":time na", 19 | "before":":time voor" 20 | } -------------------------------------------------------------------------------- /lang/ar.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"{0}سنة|{1}سنة|{2}سنتين|[3,10]:count سنوات|[11,Inf]:count سنة", 3 | "y":"{0}سنة|{1}سنة|{2}سنتين|[3,10]:count سنوات|[11,Inf]:count سنة", 4 | "month":"{0}شهر|{1} شهر|{2}شهرين|[3,10]:count أشهر|[11,Inf]:count شهر", 5 | "m":"{0}شهر|{1} شهر|{2}شهرين|[3,10]:count أشهر|[11,Inf]:count شهر", 6 | "week":"{0}إسبوع|{1}إسبوع|{2}إسبوعين|[3,10]:count أسابيع|[11,Inf]:count إسبوع", 7 | "w":"{0}إسبوع|{1}إسبوع|{2}إسبوعين|[3,10]:count أسابيع|[11,Inf]:count إسبوع", 8 | "day":"{0}يوم|{1}يوم|{2}يومين|[3,10]:count أيام|[11,Inf] يوم", 9 | "d":"{0}يوم|{1}يوم|{2}يومين|[3,10]:count أيام|[11,Inf] يوم", 10 | "hour":"{0}ساعة|{1}ساعة|{2}ساعتين|[3,10]:count ساعات|[11,Inf]:count ساعة", 11 | "h":"{0}ساعة|{1}ساعة|{2}ساعتين|[3,10]:count ساعات|[11,Inf]:count ساعة", 12 | "minute":"{0}دقيقة|{1}دقيقة|{2}دقيقتين|[3,10]:count دقائق|[11,Inf]:count دقيقة", 13 | "min":"{0}دقيقة|{1}دقيقة|{2}دقيقتين|[3,10]:count دقائق|[11,Inf]:count دقيقة", 14 | "second":"{0}ثانية|{1}ثانية|{2}ثانيتين|[3,10]:count ثوان|[11,Inf]:count ثانية", 15 | "s":"{0}ثانية|{1}ثانية|{2}ثانيتين|[3,10]:count ثوان|[11,Inf]:count ثانية", 16 | "ago":"منذ :time", 17 | "from_now":"من الآن :time", 18 | "after":"بعد :time", 19 | "before":"قبل :time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/az.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count il", 3 | "y":":count il", 4 | "month":":count ay", 5 | "m":":count ay", 6 | "week":":count həftə", 7 | "w":":count həftə", 8 | "day":":count gün", 9 | "d":":count gün", 10 | "hour":":count saat", 11 | "h":":count saat", 12 | "minute":":count dəqiqə", 13 | "min":":count dəqiqə", 14 | "second":":count saniyə", 15 | "s":":count saniyə", 16 | "ago":":time öncə", 17 | "from_now":":time sonra", 18 | "after":":time sonra", 19 | "before":":time öncə" 20 | } 21 | -------------------------------------------------------------------------------- /lang/bg.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 година|:count години", 3 | "y":"1 година|:count години", 4 | "month":"1 месец|:count месеца", 5 | "m":"1 месец|:count месеца", 6 | "week":"1 седмица|:count седмици", 7 | "w":"1 седмица|:count седмици", 8 | "day":"1 ден|:count дни", 9 | "d":"1 ден|:count дни", 10 | "hour":"1 час|:count часа", 11 | "h":"1 час|:count часа", 12 | "minute":"1 минута|:count минути", 13 | "m":"1 минута|:count минути", 14 | "second":"1 секунда|:count секунди", 15 | "s":"1 секунда|:count секунди", 16 | "ago":"преди :time", 17 | "from_now":":time от сега", 18 | "after":"след :time", 19 | "before":"преди :time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/bn.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"১ বছর|:count বছর", 3 | "y":"১ বছর|:count বছর", 4 | "month":"১ মাস|:count মাস", 5 | "m":"১ মাস|:count মাস", 6 | "week":"১ সপ্তাহ|:count সপ্তাহ", 7 | "w":"১ সপ্তাহ|:count সপ্তাহ", 8 | "day":"১ দিন|:count দিন", 9 | "d":"১ দিন|:count দিন", 10 | "hour":"১ ঘন্টা|:count ঘন্টা", 11 | "h":"১ ঘন্টা|:count ঘন্টা", 12 | "minute":"১ মিনিট|:count মিনিট", 13 | "min":"১ মিনিট|:count মিনিট", 14 | "second":"১ সেকেন্ড|:count সেকেন্ড", 15 | "s":"১ সেকেন্ড|:count সেকেন্ড", 16 | "ago":":time পূর্বে", 17 | "from_now":"এখন থেকে :time", 18 | "after":":time পরে", 19 | "before":":time আগে" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ca.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 any|:count anys", 3 | "y":"1 any|:count anys", 4 | "month":"1 mes|:count mesos", 5 | "m":"1 mes|:count mesos", 6 | "week":"1 setmana|:count setmanes", 7 | "w":"1 setmana|:count setmanes", 8 | "day":"1 dia|:count díes", 9 | "d":"1 dia|:count díes", 10 | "hour":"1 hora|:count hores", 11 | "h":"1 hora|:count hores", 12 | "minute":"1 minut|:count minuts", 13 | "min":"1 minut|:count minuts", 14 | "second":"1 segon|:count segons", 15 | "s":"1 segon|:count segons", 16 | "ago":"Fa :time", 17 | "from_now":"Dins de :time", 18 | "after":":time després", 19 | "before":":time abans" 20 | } 21 | -------------------------------------------------------------------------------- /lang/cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 rok|:count roky|:count let", 3 | "y":"1 rok|:count roky|:count let", 4 | "month":"1 měsíc|:count měsíce|:count měsíců", 5 | "m":"1 měsíc|:count měsíce|:count měsíců", 6 | "week":"1 týden|:count týdny|:count týdnů", 7 | "w":"1 týden|:count týdny|:count týdnů", 8 | "day":"1 den|:count dny|:count dní", 9 | "d":"1 den|:count dny|:count dní", 10 | "hour":"1 hodinu|:count hodiny|:count hodin", 11 | "h":"1 hodinu|:count hodiny|:count hodin", 12 | "minute":"1 minutu|:count minuty|:count minut", 13 | "min":"1 minutu|:count minuty|:count minut", 14 | "second":"1 sekundu|:count sekundy|:count sekund", 15 | "s":"1 sekundu|:count sekundy|:count sekund", 16 | "ago":":time nazpět", 17 | "from_now":"za :time", 18 | "after":":time později", 19 | "before":":time předtím" 20 | } 21 | -------------------------------------------------------------------------------- /lang/da.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 år|:count år", 3 | "y":"1 år|:count år", 4 | "month":"1 måned|:count måneder", 5 | "m":"1 måned|:count måneder", 6 | "week":"1 uge|:count uger", 7 | "w":"1 uge|:count uger", 8 | "day":"1 dag|:count dage", 9 | "d":"1 dag|:count dage", 10 | "hour":"1 time|:count timer", 11 | "h":"1 time|:count timer", 12 | "minute":"1 minut|:count minutter", 13 | "min":"1 minut|:count minutter", 14 | "second":"1 sekund|:count sekunder", 15 | "s":"1 sekund|:count sekunder", 16 | "ago":":time siden", 17 | "from_now":"om :time", 18 | "after":":time efter", 19 | "before":":time før" 20 | } 21 | -------------------------------------------------------------------------------- /lang/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 Jahr|:count Jahre", 3 | "y":"1 Jahr|:count Jahre", 4 | "month":"1 Monat|:count Monate", 5 | "m":"1 Monat|:count Monate", 6 | "week":"1 Woche|:count Wochen", 7 | "w":"1 Woche|:count Wochen", 8 | "day":"1 Tag|:count Tage", 9 | "d":"1 Tag|:count Tage", 10 | "hour":"1 Stunde|:count Stunden", 11 | "h":"1 Stunde|:count Stunden", 12 | "minute":"1 Minute|:count Minuten", 13 | "min":"1 Minute|:count Minuten", 14 | "second":"1 Sekunde|:count Sekunden", 15 | "s":"1 Sekunde|:count Sekunden", 16 | "ago":"vor :time", 17 | "from_now":"in :time", 18 | "after":":time später", 19 | "before":":time zuvor", 20 | 21 | "year_from_now":"1 Jahr|:count Jahren", 22 | "month_from_now":"1 Monat|:count Monaten", 23 | "week_from_now":"1 Woche|:count Wochen", 24 | "day_from_now":"1 Tag|:count Tagen", 25 | "year_ago":"1 Jahr|:count Jahren", 26 | "month_ago":"1 Monat|:count Monaten", 27 | "week_ago":"1 Woche|:count Wochen", 28 | "day_ago":"1 Tag|:count Tagen" 29 | } 30 | -------------------------------------------------------------------------------- /lang/el.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 χρόνος|:count χρόνια", 3 | "y":"1 χρόνος|:count χρόνια", 4 | "month":"1 μήνας|:count μήνες", 5 | "m":"1 μήνας|:count μήνες", 6 | "week":"1 εβδομάδα|:count εβδομάδες", 7 | "w":"1 εβδομάδα|:count εβδομάδες", 8 | "day":"1 μέρα|:count μέρες", 9 | "d":"1 μέρα|:count μέρες", 10 | "hour":"1 ώρα|:count ώρες", 11 | "h":"1 ώρα|:count ώρες", 12 | "minute":"1 λεπτό|:count λεπτά", 13 | "min":"1 λεπτό|:count λεπτά", 14 | "second":"1 δευτερόλεπτο|:count δευτερόλεπτα", 15 | "s":"1 δευτερόλεπτο|:count δευτερόλεπτα", 16 | "ago":"πρίν απο :time", 17 | "from_now":"σε :time απο τώρα", 18 | "after":":time μετά", 19 | "before":":time πρίν" 20 | } 21 | -------------------------------------------------------------------------------- /lang/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 year|:count years", 3 | "y":"1yr|:countyrs", 4 | "month":"1 month|:count months", 5 | "m":"1mo|:countmos", 6 | "week":"1 week|:count weeks", 7 | "w":"1w|:countw", 8 | "day":"1 day|:count days", 9 | "d":"1d|:countd", 10 | "hour":"1 hour|:count hours", 11 | "h":"1h|:counth", 12 | "minute":"1 minute|:count minutes", 13 | "min":"1m|:countm", 14 | "second":"1 second|:count seconds", 15 | "s":"1s|:counts", 16 | "ago":":time ago", 17 | "from_now":":time from now", 18 | "after":":time after", 19 | "before":":time before" 20 | } 21 | -------------------------------------------------------------------------------- /lang/eo.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 jaro|:count jaroj", 3 | "y":"1 jaro|:count jaroj", 4 | "month":"1 monato|:count monatoj", 5 | "m":"1 monato|:count monatoj", 6 | "week":"1 semajno|:count semajnoj", 7 | "w":"1 semajno|:count semajnoj", 8 | "day":"1 tago|:count tagoj", 9 | "d":"1 tago|:count tagoj", 10 | "hour":"1 horo|:count horoj", 11 | "h":"1 horo|:count horoj", 12 | "minute":"1 minuto|:count minutoj", 13 | "min":"1 minuto|:count minutoj", 14 | "second":"1 sekundo|:count sekundoj", 15 | "s":"1 sekundo|:count sekundoj", 16 | "ago":"antaŭ :time", 17 | "from_now":"je :time", 18 | "after":":time poste", 19 | "before":":time antaŭe" 20 | } 21 | -------------------------------------------------------------------------------- /lang/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 año|:count años", 3 | "y":"1 año|:count años", 4 | "month":"1 mes|:count meses", 5 | "m":"1 mes|:count meses", 6 | "week":"1 semana|:count semanas", 7 | "w":"1 semana|:count semanas", 8 | "day":"1 día|:count días", 9 | "d":"1 día|:count días", 10 | "hour":"1 hora|:count horas", 11 | "h":"1 hora|:count horas", 12 | "minute":"1 minuto|:count minutos", 13 | "min":"1 minuto|:count minutos", 14 | "second":"1 segundo|:count segundos", 15 | "s":"1 segundo|:count segundos", 16 | "ago":"hace :time", 17 | "from_now":"dentro de :time", 18 | "after":":time después", 19 | "before":":time antes" 20 | } 21 | -------------------------------------------------------------------------------- /lang/et.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 aasta|:count aastat", 3 | "y":"1 aasta|:count aastat", 4 | "month":"1 kuu|:count kuud", 5 | "m":"1 kuu|:count kuud", 6 | "week":"1 nädal|:count nädalat", 7 | "w":"1 nädal|:count nädalat", 8 | "day":"1 päev|:count päeva", 9 | "d":"1 päev|:count päeva", 10 | "hour":"1 tund|:count tundi", 11 | "h":"1 tund|:count tundi", 12 | "minute":"1 minut|:count minutit", 13 | "min":"1 minut|:count minutit", 14 | "second":"1 sekund|:count sekundit", 15 | "s":"1 sekund|:count sekundit", 16 | "ago":":time tagasi", 17 | "from_now":":time pärast", 18 | "after":":time pärast", 19 | "before":":time enne", 20 | "year_from_now":":count aasta", 21 | "month_from_now":":count kuu", 22 | "week_from_now":":count nädala", 23 | "day_from_now":":count päeva", 24 | "hour_from_now":":count tunni", 25 | "minute_from_now":":count minuti", 26 | "second_from_now":":count sekundi" 27 | } 28 | -------------------------------------------------------------------------------- /lang/eu.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"Urte 1|:count urte", 3 | "y":"Urte 1|:count urte", 4 | "month":"Hile 1|:count hile", 5 | "m":"Hile 1|:count hile", 6 | "week":"Aste 1|:count aste", 7 | "w":"Aste 1|:count aste", 8 | "day":"Egun 1|:count egun", 9 | "d":"Egun 1|:count egun", 10 | "hour":"Ordu 1|:count ordu", 11 | "h":"Ordu 1|:count ordu", 12 | "minute":"Minutu 1|:count minutu", 13 | "min":"Minutu 1|:count minutu", 14 | "second":"Segundu 1|:count segundu", 15 | "s":"Segundu 1|:count segundu", 16 | "ago":"Orain dela :time", 17 | "from_now":":time barru", 18 | "after":":time geroago", 19 | "before":":time lehenago" 20 | } 21 | -------------------------------------------------------------------------------- /lang/fa.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count سال", 3 | "y":":count سال", 4 | "month":":count ماه", 5 | "m":":count ماه", 6 | "week":":count هفته", 7 | "w":":count هفته", 8 | "day":":count روز", 9 | "d":":count روز", 10 | "hour":":count ساعت", 11 | "h":":count ساعت", 12 | "minute":":count دقیقه", 13 | "min":":count دقیقه", 14 | "second":":count ثانیه", 15 | "s":":count ثانیه", 16 | "ago":":time پیش", 17 | "from_now":":time بعد", 18 | "after":":time پس از", 19 | "before":":time پیش از" 20 | } 21 | -------------------------------------------------------------------------------- /lang/fi.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 vuosi|:count vuotta", 3 | "y":"1 vuosi|:count vuotta", 4 | "month":"1 kuukausi|:count kuukautta", 5 | "m":"1 kuukausi|:count kuukautta", 6 | "week":"1 viikko|:count viikkoa", 7 | "w":"1 viikko|:count viikkoa", 8 | "day":"1 päivä|:count päivää", 9 | "d":"1 päivä|:count päivää", 10 | "hour":"1 tunti|:count tuntia", 11 | "h":"1 tunti|:count tuntia", 12 | "minute":"1 minuutti|:count minuuttia", 13 | "min":"1 minuutti|:count minuuttia", 14 | "second":"1 sekunti|:count sekuntia", 15 | "s":"1 sekunti|:count sekuntia", 16 | "ago":":time sitten", 17 | "from_now":":time tästä hetkestä", 18 | "after":":time sen jälkeen", 19 | "before":":time ennen" 20 | } 21 | -------------------------------------------------------------------------------- /lang/fo.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 ár|:count ár", 3 | "y":"1 ár|:count ár", 4 | "month":"1 mánaður|:count mánaðir", 5 | "m":"1 mánaður|:count mánaðir", 6 | "week":"1 vika|:count vikur", 7 | "w":"1 vika|:count vikur", 8 | "day":"1 dag|:count dagar", 9 | "d":"1 dag|:count dagar", 10 | "hour":"1 tími|:count tímar", 11 | "h":"1 tími|:count tímar", 12 | "minute":"1 minutt|:count minuttir", 13 | "min":"1 minutt|:count minuttir", 14 | "second":"1 sekund|:count sekundir", 15 | "s":"1 sekund|:count sekundir", 16 | "ago":":time síðan", 17 | "from_now":"um :time", 18 | "after":":time aftaná", 19 | "before":":time áðrenn" 20 | } 21 | -------------------------------------------------------------------------------- /lang/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 an|:count ans", 3 | "y":"1 an|:count ans", 4 | "month":":count mois", 5 | "m":":count mois", 6 | "week":"1 semaine|:count semaines", 7 | "w":"1 semaine|:count semaines", 8 | "day":"1 jour|:count jours", 9 | "d":"1 jour|:count jours", 10 | "hour":"1 heure|:count heures", 11 | "h":"1 heure|:count heures", 12 | "minute":"1 minute|:count minutes", 13 | "min":"1 minute|:count minutes", 14 | "second":"1 seconde|:count secondes", 15 | "s":"1 seconde|:count secondes", 16 | "ago":"il y a :time", 17 | "from_now":"dans :time", 18 | "after":":time après", 19 | "before":":time avant" 20 | } 21 | -------------------------------------------------------------------------------- /lang/gl.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 ano|:count anos", 3 | "month":"1 mes|:count meses", 4 | "week":"1 semana|:count semanas", 5 | "day":"1 día|:count días", 6 | "hour":"1 hora|:count horas", 7 | "minute":"1 minuto|:count minutos", 8 | "second":"1 segundo|:count segundos", 9 | "ago":"fai :time", 10 | "from_now":"dentro de :time", 11 | "after":":time despois", 12 | "before":":time antes" 13 | } 14 | -------------------------------------------------------------------------------- /lang/he.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"שנה|{2}שנתיים|:count שנים", 3 | "y":"שנה|{2}שנתיים|:count שנים", 4 | "month":"חודש|{2}חודשיים|:count חודשים", 5 | "m":"חודש|{2}חודשיים|:count חודשים", 6 | "week":"שבוע|{2}שבועיים|:count שבועות", 7 | "w":"שבוע|{2}שבועיים|:count שבועות", 8 | "day":"יום|{2}יומיים|:count ימים", 9 | "d":"יום|{2}יומיים|:count ימים", 10 | "hour":"שעה|{2}שעתיים|:count שעות", 11 | "h":"שעה|{2}שעתיים|:count שעות", 12 | "minute":"דקה|{2}דקותיים|:count דקות", 13 | "min":"דקה|{2}דקותיים|:count דקות", 14 | "second":"שניה|:count שניות", 15 | "s":"שניה|:count שניות", 16 | "ago":"לפני :time", 17 | "from_now":"בעוד :time", 18 | "after":"אחרי :time", 19 | "before":"לפני :time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/hr.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count godinu|:count godine|:count godina", 3 | "y":":count godinu|:count godine|:count godina", 4 | "month":":count mjesec|:count mjeseca|:count mjeseci", 5 | "m":":count mjesec|:count mjeseca|:count mjeseci", 6 | "week":":count tjedan|:count tjedna|:count tjedana", 7 | "w":":count tjedan|:count tjedna|:count tjedana", 8 | "day":":count dan|:count dana|:count dana", 9 | "d":":count dan|:count dana|:count dana", 10 | "hour":":count sat|:count sata|:count sati", 11 | "h":":count sat|:count sata|:count sati", 12 | "minute":":count minutu|:count minute |:count minuta", 13 | "min":":count minutu|:count minute |:count minuta", 14 | "second":":count sekundu|:count sekunde|:count sekundi", 15 | "s":":count sekundu|:count sekunde|:count sekundi", 16 | "ago":"prije :time", 17 | "from_now":"za :time", 18 | "after":"za :time", 19 | "before":"prije :time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/hu.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count év", 3 | "y":":count év", 4 | "month":":count hónap", 5 | "m":":count hónap", 6 | "week":":count hét", 7 | "w":":count hét", 8 | "day":":count nap", 9 | "d":":count nap", 10 | "hour":":count óra", 11 | "h":":count óra", 12 | "minute":":count perc", 13 | "min":":count perc", 14 | "second":":count másodperc", 15 | "s":":count másodperc", 16 | "ago":":time", 17 | "from_now":":time múlva", 18 | "after":":time később", 19 | "before":":time korábban", 20 | "year_ago":":count éve", 21 | "month_ago":":count hónapja", 22 | "week_ago":":count hete", 23 | "day_ago":":count napja", 24 | "hour_ago":":count órája", 25 | "minute_ago":":count perce", 26 | "second_ago":":count másodperce", 27 | "year_after":":count évvel", 28 | "month_after":":count hónappal", 29 | "week_after":":count héttel", 30 | "day_after":":count nappal", 31 | "hour_after":":count órával", 32 | "minute_after":":count perccel", 33 | "second_after":":count másodperccel", 34 | "year_before":":count évvel", 35 | "month_before":":count hónappal", 36 | "week_before":":count héttel", 37 | "day_before":":count nappal", 38 | "hour_before":":count órával", 39 | "minute_before":":count perccel", 40 | "second_before":":count másodperccel" 41 | } 42 | -------------------------------------------------------------------------------- /lang/hy.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count տարի", 3 | "y":":count տարի", 4 | "month":":count ամիս", 5 | "m":":count ամիս", 6 | "week":":count շաբաթ", 7 | "w":":count շաբաթ", 8 | "day":":count օր", 9 | "d":":count օր", 10 | "hour":":count ժամ", 11 | "h":":count ժամ", 12 | "minute":":count րոպե", 13 | "min":":count րոպե", 14 | "second":":count վայրկյան", 15 | "s":":count վայրկյան", 16 | "ago":":time առաջ", 17 | "from_now":":time հետո", 18 | "after":":time հետո", 19 | "before":":time առաջ" 20 | } 21 | -------------------------------------------------------------------------------- /lang/id.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count tahun", 3 | "y":":count tahun", 4 | "month":":count bulan", 5 | "m":":count bulan", 6 | "week":":count minggu", 7 | "w":":count minggu", 8 | "day":":count hari", 9 | "d":":count hari", 10 | "hour":":count jam", 11 | "h":":count jam", 12 | "minute":":count menit", 13 | "min":":count menit", 14 | "second":":count detik", 15 | "s":":count detik", 16 | "ago":":time yang lalu", 17 | "from_now":":time dari sekarang", 18 | "after":":time setelah", 19 | "before":":time sebelum" 20 | } 21 | -------------------------------------------------------------------------------- /lang/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 anno|:count anni", 3 | "y":"1 anno|:count anni", 4 | "month":"1 mese|:count mesi", 5 | "m":"1 mese|:count mesi", 6 | "week":"1 settimana|:count settimane", 7 | "w":"1 settimana|:count settimane", 8 | "day":"1 giorno|:count giorni", 9 | "d":"1 giorno|:count giorni", 10 | "hour":"1 ora|:count ore", 11 | "h":"1 ora|:count ore", 12 | "minute":"1 minuto|:count minuti", 13 | "min":"1 minuto|:count minuti", 14 | "second":"1 secondo|:count secondi", 15 | "s":"1 secondo|:count secondi", 16 | "ago":":time fa", 17 | "from_now":":time da adesso", 18 | "after":":time dopo", 19 | "before":":time prima" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count 年", 3 | "y":":count 年", 4 | "month":":count ヶ月", 5 | "m":":count ヶ月", 6 | "week":":count 週間", 7 | "w":":count 週間", 8 | "day":":count 日", 9 | "d":":count 日", 10 | "hour":":count 時間", 11 | "h":":count 時間", 12 | "minute":":count 分", 13 | "min":":count 分", 14 | "second":":count 秒", 15 | "s":":count 秒", 16 | "ago":":time 前", 17 | "from_now":"今から :time", 18 | "after":":time 後", 19 | "before":":time 前" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ka.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count წლის", 3 | "y":":count წლის", 4 | "month":":count თვის", 5 | "m":":count თვის", 6 | "week":":count კვირის", 7 | "w":":count კვირის", 8 | "day":":count დღის", 9 | "d":":count დღის", 10 | "hour":":count საათის", 11 | "h":":count საათის", 12 | "minute":":count წუთის", 13 | "min":":count წუთის", 14 | "second":":count წამის", 15 | "s":":count წამის", 16 | "ago":":time უკან", 17 | "from_now":":time შემდეგ", 18 | "after":":time შემდეგ", 19 | "before":":time უკან" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ko.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count 년", 3 | "y":":count 년", 4 | "month":":count 개월", 5 | "m":":count 개월", 6 | "week":":count 주일", 7 | "w":":count 주일", 8 | "day":":count 일", 9 | "d":":count 일", 10 | "hour":":count 시간", 11 | "h":":count 시간", 12 | "minute":":count 분", 13 | "min":":count 분", 14 | "second":":count 초", 15 | "s":":count 초", 16 | "ago":":time 전", 17 | "from_now":":time 후", 18 | "after":":time 뒤", 19 | "before":":time 앞" 20 | } 21 | -------------------------------------------------------------------------------- /lang/loader.go: -------------------------------------------------------------------------------- 1 | package lang 2 | 3 | import ( 4 | "embed" 5 | "errors" 6 | ) 7 | 8 | //go:embed *.json 9 | var f embed.FS 10 | 11 | // LoadLocaleText will load the translations from the locale json files according to the locale 12 | func LoadLocaleText(l string) ([]byte, error) { 13 | lText, err := f.ReadFile(l + ".json") 14 | 15 | if err != nil { 16 | return nil, errors.New("not able to read the lang file:" + err.Error()) 17 | } 18 | 19 | return lText, nil 20 | } 21 | -------------------------------------------------------------------------------- /lang/lt.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count metus|:count metus|:count metų", 3 | "y":":count metus|:count metus|:count metų", 4 | "month":":count mėnesį|:count mėnesius|:count mėnesių", 5 | "m":":count mėnesį|:count mėnesius|:count mėnesių", 6 | "week":":count savaitę|:count savaites|:count savaičių", 7 | "w":":count savaitę|:count savaites|:count savaičių", 8 | "day":":count dieną|:count dienas|:count dienų", 9 | "d":":count dieną|:count dienas|:count dienų", 10 | "hour":":count valandą|:count valandas|:count valandų", 11 | "h":":count valandą|:count valandas|:count valandų", 12 | "minute":":count minutę|:count minutes|:count minučių", 13 | "min":":count minutę|:count minutes|:count minučių", 14 | "second":":count sekundę|:count sekundes|:count sekundžių", 15 | "s":":count sekundę|:count sekundes|:count sekundžių", 16 | "second_from_now":":count sekundės|:count sekundžių|:count sekundžių", 17 | "minute_from_now":":count minutės|:count minučių|:count minučių", 18 | "hour_from_now":":count valandos|:count valandų|:count valandų", 19 | "day_from_now":":count dienos|:count dienų|:count dienų", 20 | "week_from_now":":count savaitės|:count savaičių|:count savaičių", 21 | "month_from_now":":count mėnesio|:count mėnesių|:count mėnesių", 22 | "year_from_now":":count metų", 23 | "ago":"prieš :time", 24 | "from_now":"už :time", 25 | "after":"po :time", 26 | "before":":time nuo dabar" 27 | } 28 | -------------------------------------------------------------------------------- /lang/lv.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"0 gadiem|:count gada|:count gadiem", 3 | "y":"0 gadiem|:count gada|:count gadiem", 4 | "month":"0 mēnešiem|:count mēneša|:count mēnešiem", 5 | "m":"0 mēnešiem|:count mēneša|:count mēnešiem", 6 | "week":"0 nedēļām|:count nedēļas|:count nedēļām", 7 | "w":"0 nedēļām|:count nedēļas|:count nedēļām", 8 | "day":"0 dienām|:count dienas|:count dienām", 9 | "d":"0 dienām|:count dienas|:count dienām", 10 | "hour":"0 stundām|:count stundas|:count stundām", 11 | "h":"0 stundām|:count stundas|:count stundām", 12 | "minute":"0 minūtēm|:count minūtes|:count minūtēm", 13 | "min":"0 minūtēm|:count minūtes|:count minūtēm", 14 | "second":"0 sekundēm|:count sekundes|:count sekundēm", 15 | "s":"0 sekundēm|:count sekundes|:count sekundēm", 16 | "ago":"pirms :time", 17 | "from_now":"pēc :time", 18 | "after":":time vēlāk", 19 | "before":":time pirms", 20 | 21 | "year_after":"0 gadus|:count gadu|:count gadus", 22 | "month_after":"0 mēnešus|:count mēnesi|:count mēnešus", 23 | "week_after":"0 nedēļas|:count nedēļu|:count nedēļas", 24 | "day_after":"0 dienas|:count dienu|:count dienas", 25 | "hour_after":"0 stundas|:count stundu|:count stundas", 26 | "minute_after":"0 minūtes|:count minūti|:count minūtes", 27 | "second_after":"0 sekundes|:count sekundi|:count sekundes", 28 | 29 | "year_before":"0 gadus|:count gadu|:count gadus", 30 | "month_before":"0 mēnešus|:count mēnesi|:count mēnešus", 31 | "week_before":"0 nedēļas|:count nedēļu|:count nedēļas", 32 | "day_before":"0 dienas|:count dienu|:count dienas", 33 | "hour_before":"0 stundas|:count stundu|:count stundas", 34 | "minute_before":"0 minūtes|:count minūti|:count minūtes", 35 | "second_before":"0 sekundes|:count sekundi|:count sekundes" 36 | } 37 | -------------------------------------------------------------------------------- /lang/mk.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 година|:count години", 3 | "month":"1 месец|:count месеци", 4 | "week":"1 седмица|:count седмици", 5 | "day":"1 ден|:count дена", 6 | "hour":"1 час|:count часа", 7 | "minute":"1 минута|:count минути", 8 | "second":"1 секунда|:count секунди", 9 | "ago":"пред :time", 10 | "from_now":":time од сега", 11 | "after":"по :time", 12 | "before":"пред :time" 13 | } 14 | -------------------------------------------------------------------------------- /lang/ms.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count tahun", 3 | "y":":count tahun", 4 | "month":":count bulan", 5 | "m":":count bulan", 6 | "week":":count minggu", 7 | "w":":count minggu", 8 | "day":":count hari", 9 | "d":":count hari", 10 | "hour":":count jam", 11 | "h":":count jam", 12 | "minute":":count minit", 13 | "min":":count minit", 14 | "second":":count saat", 15 | "s":":count saat", 16 | "ago":":time yang lalu", 17 | "from_now":":time dari sekarang", 18 | "after":":time selepas", 19 | "before":":time sebelum" 20 | } 21 | -------------------------------------------------------------------------------- /lang/nl.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count jaar", 3 | "y":":count jaar", 4 | "month":"1 maand|:count maanden", 5 | "m":"1 maand|:count maanden", 6 | "week":"1 week|:count weken", 7 | "w":"1 week|:count weken", 8 | "day":"1 dag|:count dagen", 9 | "d":"1 dag|:count dagen", 10 | "hour":":count uur", 11 | "h":":count uur", 12 | "minute":"1 minuut|:count minuten", 13 | "min":"1 minuut|:count minuten", 14 | "second":"1 seconde|:count seconden", 15 | "s":"1 seconde|:count seconden", 16 | "ago":":time geleden", 17 | "from_now":"over :time", 18 | "after":":time later", 19 | "before":":time eerder" 20 | } 21 | -------------------------------------------------------------------------------- /lang/no.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 år|:count år", 3 | "y":"1 år|:count år", 4 | "month":"1 måned|:count måneder", 5 | "m":"1 måned|:count måneder", 6 | "week":"1 uke|:count uker", 7 | "w":"1 uke|:count uker", 8 | "day":"1 dag|:count dager", 9 | "d":"1 dag|:count dager", 10 | "hour":"1 time|:count timer", 11 | "h":"1 time|:count timer", 12 | "minute":"1 minutt|:count minutter", 13 | "min":"1 minutt|:count minutter", 14 | "second":"1 sekund|:count sekunder", 15 | "s":"1 sekund|:count sekunder", 16 | "ago":":time siden", 17 | "from_now":"om :time", 18 | "after":":time etter", 19 | "before":":time før" 20 | } 21 | -------------------------------------------------------------------------------- /lang/pl.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 rok|:count lata|:count lat", 3 | "y":"1 rok|:count lata|:count lat", 4 | "month":"1 miesiąc|:count miesiące|:count miesięcy", 5 | "m":"1 miesiąc|:count miesiące|:count miesięcy", 6 | "week":"1 tydzień|:count tygodnie|:count tygodni", 7 | "w":"1 tydzień|:count tygodnie|:count tygodni", 8 | "day":"1 dzień|:count dni|:count dni", 9 | "d":"1 dzień|:count dni|:count dni", 10 | "hour":"1 godzina|:count godziny|:count godzin", 11 | "h":"1 godzina|:count godziny|:count godzin", 12 | "minute":"1 minuta|:count minuty|:count minut", 13 | "min":"1 minuta|:count minuty|:count minut", 14 | "second":"1 sekunda|:count sekundy|:count sekund", 15 | "s":"1 sekunda|:count sekundy|:count sekund", 16 | "ago":":time temu", 17 | "from_now":":time od teraz", 18 | "after":":time przed", 19 | "before":":time po" 20 | } 21 | -------------------------------------------------------------------------------- /lang/pt.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 ano|:count anos", 3 | "y":"1 ano|:count anos", 4 | "month":"1 mês|:count meses", 5 | "m":"1 mês|:count meses", 6 | "week":"1 semana|:count semanas", 7 | "w":"1 semana|:count semanas", 8 | "day":"1 dia|:count dias", 9 | "d":"1 dia|:count dias", 10 | "hour":"1 hora|:count horas", 11 | "h":"1 hora|:count horas", 12 | "minute":"1 minuto|:count minutos", 13 | "min":"1 minuto|:count minutos", 14 | "second":"1 segundo|:count segundos", 15 | "s":"1 segundo|:count segundos", 16 | "ago":":time atrás", 17 | "from_now":"em :time", 18 | "after":":time depois", 19 | "before":":time antes" 20 | } 21 | -------------------------------------------------------------------------------- /lang/pt_BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 ano|:count anos", 3 | "y":"1 ano|:count anos", 4 | "month":"1 mês|:count meses", 5 | "m":"1 mês|:count meses", 6 | "week":"1 semana|:count semanas", 7 | "w":"1 semana|:count semanas", 8 | "day":"1 dia|:count dias", 9 | "d":"1 dia|:count dias", 10 | "hour":"1 hora|:count horas", 11 | "h":"1 hora|:count horas", 12 | "minute":"1 minuto|:count minutos", 13 | "min":"1 minuto|:count minutos", 14 | "second":"1 segundo|:count segundos", 15 | "s":"1 segundo|:count segundos", 16 | "ago":"há :time", 17 | "from_now":"em :time", 18 | "after":"após :time", 19 | "before":":time atrás" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ro.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"un an|:count ani|:count ani", 3 | "y":"un an|:count ani|:count ani", 4 | "month":"o lună|:count luni|:count luni", 5 | "m":"o lună|:count luni|:count luni", 6 | "week":"o săptămână|:count săptămâni|:count săptămâni", 7 | "w":"o săptămână|:count săptămâni|:count săptămâni", 8 | "day":"o zi|:count zile|:count zile", 9 | "d":"o zi|:count zile|:count zile", 10 | "hour":"o oră|:count ore|:count ore", 11 | "h":"o oră|:count ore|:count ore", 12 | "minute":"un minut|:count minute|:count minute", 13 | "min":"un minut|:count minute|:count minute", 14 | "second":"o secundă|:count secunde|:count secunde", 15 | "s":"o secundă|:count secunde|:count secunde", 16 | "ago":"acum :time", 17 | "from_now":":time de acum", 18 | "after":"peste :time", 19 | "before":"acum :time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ru.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count год|:count года|:count лет", 3 | "y":":count год|:count года|:count лет", 4 | "month":":count месяц|:count месяца|:count месяцев", 5 | "m":":count месяц|:count месяца|:count месяцев", 6 | "week":":count неделю|:count недели|:count недель", 7 | "w":":count неделю|:count недели|:count недель", 8 | "day":":count день|:count дня|:count дней", 9 | "d":":count день|:count дня|:count дней", 10 | "hour":":count час|:count часа|:count часов", 11 | "h":":count час|:count часа|:count часов", 12 | "minute":":count минуту|:count минуты|:count минут", 13 | "min":":count минуту|:count минуты|:count минут", 14 | "second":":count секунду|:count секунды|:count секунд", 15 | "s":":count секунду|:count секунды|:count секунд", 16 | "ago":":time назад", 17 | "from_now":"через :time", 18 | "after":":time после", 19 | "before":":time до" 20 | } 21 | -------------------------------------------------------------------------------- /lang/sk.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"rok|:count roky|:count rokov", 3 | "y":"rok|:count roky|:count rokov", 4 | "month":"mesiac|:count mesiace|:count mesiacov", 5 | "m":"mesiac|:count mesiace|:count mesiacov", 6 | "week":"týždeň|:count týždne|:count týždňov", 7 | "w":"týždeň|:count týždne|:count týždňov", 8 | "day":"deň|:count dni|:count dní", 9 | "d":"deň|:count dni|:count dní", 10 | "hour":"hodinu|:count hodiny|:count hodín", 11 | "h":"hodinu|:count hodiny|:count hodín", 12 | "minute":"minútu|:count minúty|:count minút", 13 | "min":"minútu|:count minúty|:count minút", 14 | "second":"sekundu|:count sekundy|:count sekúnd", 15 | "s":"sekundu|:count sekundy|:count sekúnd", 16 | "ago":"pred :time", 17 | "from_now":"za :time", 18 | "after":":time neskôr", 19 | "before":":time predtým" 20 | } 21 | -------------------------------------------------------------------------------- /lang/sl.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count leto|:count leti|:count leta|:count let", 3 | "y":":count leto|:count leti|:count leta|:count let", 4 | "month":":count mesec|:count meseca|:count mesece|:count mesecev", 5 | "m":":count mesec|:count meseca|:count mesece|:count mesecev", 6 | "week":":count teden|:count tedna|:count tedne|:count tednov", 7 | "w":":count teden|:count tedna|:count tedne|:count tednov", 8 | "day":":count dan|:count dni|:count dni|:count dni", 9 | "d":":count dan|:count dni|:count dni|:count dni", 10 | "hour":":count uro|:count uri|:count ure|:count ur", 11 | "h":":count uro|:count uri|:count ure|:count ur", 12 | "minute":":count minuto|:count minuti|:count minute|:count minut", 13 | "min":":count minuto|:count minuti|:count minute|:count minut", 14 | "second":":count sekundo|:count sekundi|:count sekunde|:count sekund", 15 | "s":":count sekundo|:count sekundi|:count sekunde|:count sekund", 16 | "year_ago":":count letom|:count leti|:count leti|:count leti", 17 | "month_ago":":count mesecem|:count meseci|:count meseci|:count meseci", 18 | "week_ago":":count tednom|:count tednoma|:count tedni|:count tedni", 19 | "day_ago":":count dnem|:count dnevoma|:count dnevi|:count dnevi", 20 | "hour_ago":":count uro|:count urama|:count urami|:count urami", 21 | "minute_ago":":count minuto|:count minutama|:count minutami|:count minutami", 22 | "second_ago":":count sekundo|:count sekundama|:count sekundami|:count sekundami", 23 | "ago":"pred :time", 24 | "from_now":"čez :time", 25 | "after":"čez :time", 26 | "before":"pred :time" 27 | } 28 | -------------------------------------------------------------------------------- /lang/sq.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 vit|:count vjet", 3 | "y":"1 vit|:count vjet", 4 | "month":"1 muaj|:count muaj", 5 | "m":"1 muaj|:count muaj", 6 | "week":"1 javë|:count javë", 7 | "w":"1 javë|:count javë", 8 | "day":"1 ditë|:count ditë", 9 | "d":"1 ditë|:count ditë", 10 | "hour":"1 orë|:count orë", 11 | "h":"1 orë|:count orë", 12 | "minute":"1 minutë|:count minuta", 13 | "min":"1 minutë|:count minuta", 14 | "second":"1 sekondë|:count sekonda", 15 | "s":"1 sekondë|:count sekonda", 16 | "ago":":time më parë", 17 | "from_now":":time nga tani", 18 | "after":":time pas", 19 | "before":":time para" 20 | } 21 | -------------------------------------------------------------------------------- /lang/sr.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count godina|:count godine|:count godina", 3 | "y":":count godina|:count godine|:count godina", 4 | "month":":count mesec|:count meseca|:count meseci", 5 | "m":":count mesec|:count meseca|:count meseci", 6 | "week":":count nedelja|:count nedelje|:count nedelja", 7 | "w":":count nedelja|:count nedelje|:count nedelja", 8 | "day":":count dan|:count dana|:count dana", 9 | "d":":count dan|:count dana|:count dana", 10 | "hour":":count sat|:count sata|:count sati", 11 | "h":":count sat|:count sata|:count sati", 12 | "minute":":count minut|:count minuta |:count minuta", 13 | "min":":count minut|:count minuta |:count minuta", 14 | "second":":count sekund|:count sekunde|:count sekunde", 15 | "s":":count sekund|:count sekunde|:count sekunde", 16 | "ago":"pre :time", 17 | "from_now":":time od sada", 18 | "after":"nakon :time", 19 | "before":"pre :time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/sv.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 år|:count år", 3 | "y":"1 år|:count år", 4 | "month":"1 månad|:count månader", 5 | "m":"1 månad|:count månader", 6 | "week":"1 vecka|:count veckor", 7 | "w":"1 vecka|:count veckor", 8 | "day":"1 dag|:count dagar", 9 | "d":"1 dag|:count dagar", 10 | "hour":"1 timme|:count timmar", 11 | "h":"1 timme|:count timmar", 12 | "minute":"1 minut|:count minuter", 13 | "min":"1 minut|:count minuter", 14 | "second":"1 sekund|:count sekunder", 15 | "s":"1 sekund|:count sekunder", 16 | "ago":":time sedan", 17 | "from_now":"om :time", 18 | "after":":time efter", 19 | "before":":time före" 20 | } 21 | -------------------------------------------------------------------------------- /lang/th.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":"1 ปี|:count ปี", 3 | "y":"1 ปี|:count ปี", 4 | "month":"1 เดือน|:count เดือน", 5 | "m":"1 เดือน|:count เดือน", 6 | "week":"1 สัปดาห์|:count สัปดาห์", 7 | "w":"1 สัปดาห์|:count สัปดาห์", 8 | "day":"1 วัน|:count วัน", 9 | "d":"1 วัน|:count วัน", 10 | "hour":"1 ชั่วโมง|:count ชั่วโมง", 11 | "h":"1 ชั่วโมง|:count ชั่วโมง", 12 | "minute":"1 นาที|:count นาที", 13 | "min":"1 นาที|:count นาที", 14 | "second":"1 วินาที|:count วินาที", 15 | "s":"1 วินาที|:count วินาที", 16 | "ago":":time ที่แล้ว", 17 | "from_now":":time จากนี้", 18 | "after":"หลัง:time", 19 | "before":"ก่อน:time" 20 | } 21 | -------------------------------------------------------------------------------- /lang/tr.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count yıl", 3 | "y":":count yıl", 4 | "month":":count ay", 5 | "m":":count ay", 6 | "week":":count hafta", 7 | "w":":count hafta", 8 | "day":":count gün", 9 | "d":":count gün", 10 | "hour":":count saat", 11 | "h":":count saat", 12 | "minute":":count dakika", 13 | "min":":count dakika", 14 | "second":":count saniye", 15 | "s":":count saniye", 16 | "ago":":time önce", 17 | "from_now":":time sonra", 18 | "after":":time sonra", 19 | "before":":time önce" 20 | } 21 | -------------------------------------------------------------------------------- /lang/uk.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count рік|:count роки|:count років", 3 | "y":":count рік|:count роки|:count років", 4 | "month":":count місяць|:count місяці|:count місяців", 5 | "m":":count місяць|:count місяці|:count місяців", 6 | "week":":count тиждень|:count тижні|:count тижнів", 7 | "w":":count тиждень|:count тижні|:count тижнів", 8 | "day":":count день|:count дні|:count днів", 9 | "d":":count день|:count дні|:count днів", 10 | "hour":":count година|:count години|:count годин", 11 | "h":":count година|:count години|:count годин", 12 | "minute":":count хвилину|:count хвилини|:count хвилин", 13 | "min":":count хвилину|:count хвилини|:count хвилин", 14 | "second":":count секунду|:count секунди|:count секунд", 15 | "s":":count секунду|:count секунди|:count секунд", 16 | "ago":":time назад", 17 | "from_now":"через :time", 18 | "after":":time після", 19 | "before":":time до" 20 | } 21 | -------------------------------------------------------------------------------- /lang/ur.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count سال", 3 | "month":":count ماه", 4 | "week":":count ہفتے", 5 | "day":":count روز", 6 | "hour":":count گھنٹے", 7 | "minute":":count منٹ", 8 | "second":":count سیکنڈ", 9 | "ago":":time پہلے", 10 | "from_now":":time بعد", 11 | "after":":time بعد", 12 | "before":":time پہلے" 13 | } 14 | -------------------------------------------------------------------------------- /lang/uz.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count yil|:count yil|:count yil", 3 | "y":":count yil|:count yil|:count yil", 4 | "month":":count oy|:count oy|:count oylar", 5 | "m":":count oy|:count oy|:count oylar", 6 | "week":":count hafta|:count hafta|:count hafta", 7 | "w":":count hafta|:count hafta|:count hafta", 8 | "day":":count kun|:count kun|:count kun", 9 | "d":":count kun|:count kun|:count kun", 10 | "hour":":count soat|:count soat|:count soat", 11 | "h":":count soat|:count soat|:count soat", 12 | "minute":":count minut|:count minut|:count minut", 13 | "min":":count minut|:count minut|:count minut", 14 | "second":":count sekund|:count sekund|:count sekund", 15 | "s":":count sekund|:count sekund|:count sekund", 16 | "ago":":time avval", 17 | "from_now":"keyin :time", 18 | "after":":time keyin", 19 | "before":":time gacha" 20 | } 21 | -------------------------------------------------------------------------------- /lang/vi.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count năm", 3 | "y":":count năm", 4 | "month":":count tháng", 5 | "m":":count tháng", 6 | "week":":count tuần", 7 | "w":":count tuần", 8 | "day":":count ngày", 9 | "d":":count ngày", 10 | "hour":":count giờ", 11 | "h":":count giờ", 12 | "minute":":count phút", 13 | "min":":count phút", 14 | "second":":count giây", 15 | "s":":count giây", 16 | "ago":":time trước", 17 | "from_now":":time từ bây giờ", 18 | "after":":time sau", 19 | "before":":time trước" 20 | } 21 | -------------------------------------------------------------------------------- /lang/zh.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count年", 3 | "y":":count年", 4 | "month":":count个月", 5 | "m":":count个月", 6 | "week":":count周", 7 | "w":":count周", 8 | "day":":count天", 9 | "d":":count天", 10 | "hour":":count小时", 11 | "h":":count小时", 12 | "minute":":count分钟", 13 | "min":":count分钟", 14 | "second":":count秒", 15 | "s":":count秒", 16 | "ago":":time前", 17 | "from_now":"距现在:time", 18 | "after":":time后", 19 | "before":":time前" 20 | } -------------------------------------------------------------------------------- /lang/zh_TW.json: -------------------------------------------------------------------------------- 1 | { 2 | "year":":count 年", 3 | "y":":count 年", 4 | "month":":count 月", 5 | "m":":count 月", 6 | "week":":count 周", 7 | "w":":count 周", 8 | "day":":count 天", 9 | "d":":count 天", 10 | "hour":":count 小時", 11 | "h":":count 小時", 12 | "minute":":count 分鐘", 13 | "min":":count 分鐘", 14 | "second":":count 秒", 15 | "s":":count 秒", 16 | "ago":":time前", 17 | "from_now":"距現在 :time", 18 | "after":":time後", 19 | "before":":time前" 20 | } 21 | -------------------------------------------------------------------------------- /translator.go: -------------------------------------------------------------------------------- 1 | package carbon 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "regexp" 7 | "strconv" 8 | "strings" 9 | 10 | "github.com/uniplaces/carbon/lang" 11 | ) 12 | 13 | // Translator helps to translate time based on locale 14 | type Translator struct { 15 | locale string 16 | cacheDir string 17 | resources map[string]string 18 | } 19 | 20 | // NewTranslator returns a initialized instance of Translator 21 | func NewTranslator() *Translator { 22 | return &Translator{ 23 | resources: make(map[string]string), 24 | } 25 | } 26 | 27 | // GetLocale will return locale of a Translator 28 | func (t *Translator) GetLocale() string { 29 | return t.locale 30 | } 31 | 32 | // SetLocale will set locale on a Translator 33 | func (t *Translator) SetLocale(l string) error { 34 | err := t.AssertValidLocale(l) 35 | if err != nil { 36 | return err 37 | } 38 | 39 | err = t.loadResource(l) 40 | if err != nil { 41 | return err 42 | } 43 | 44 | t.locale = l 45 | 46 | return nil 47 | } 48 | 49 | // AssertValidLocale checks if the locale is valid or not 50 | func (t *Translator) AssertValidLocale(l string) error { 51 | matched, err := regexp.MatchString("^(?:[a-z]{2}|[a-z]{2}(([_-]{1})([a-zA-Z]{2}){1,2}))$", l) 52 | if err != nil { 53 | return errors.New("unable to match locale code : " + err.Error()) 54 | } 55 | if !matched { 56 | return errors.New("invalid locale code : " + l) 57 | } 58 | 59 | return nil 60 | } 61 | 62 | // loadResource loads the translations according to the locale 63 | func (t *Translator) loadResource(l string) error { 64 | lText, err := lang.LoadLocaleText(l) 65 | if err != nil { 66 | return err 67 | } 68 | 69 | err = json.Unmarshal(lText, &t.resources) 70 | if err != nil { 71 | return errors.New("unable to unmarshall locale data : " + err.Error()) 72 | } 73 | 74 | return nil 75 | } 76 | 77 | // chooseUnit will choose unit of translations according to the count 78 | func (t *Translator) chooseUnit(unit string, count int64) (string, error) { 79 | s := strings.Split(t.resources[unit], "|") 80 | if count > 1 { 81 | return strings.Replace(s[1], ":count", strconv.FormatInt(int64(count), 10), 1), nil 82 | } 83 | 84 | return s[0], nil 85 | } 86 | 87 | // chooseTrans will choose the word to make a diffForHumans statement 88 | func (t *Translator) chooseTrans(transID, time string) string { 89 | return strings.Replace(t.resources[transID], ":time", time, 1) 90 | } 91 | -------------------------------------------------------------------------------- /translator_test.go: -------------------------------------------------------------------------------- 1 | package carbon 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestLoadResource(t *testing.T) { 12 | tr := NewTranslator() 13 | err := tr.loadResource("pt_BR") 14 | assert.Nil(t, err) 15 | } 16 | 17 | func TestTrans(t *testing.T) { 18 | c, _ := Create(2009, time.November, 10, 23, 0, 0, 0, "UTC") 19 | c.SetLocale("pt") 20 | assert.Equal(t, "pt", c.GetLocale()) 21 | } 22 | 23 | func TestLoadNonExistentResource(t *testing.T) { 24 | tr := NewTranslator() 25 | err := tr.loadResource("iv") 26 | assert.NotNil(t, err) 27 | assert.True(t, strings.Contains(err.Error(), "open iv.json: file does not exist")) 28 | } 29 | --------------------------------------------------------------------------------