1
0
mirror of https://github.com/ManyakRus/crud_generator.git synced 2025-10-31 00:17:48 +02:00

сделал Path_Linux_to_Windows()

This commit is contained in:
Sanek
2025-07-07 09:36:34 +03:00
parent 5726fbcf42
commit d3be61c196
199 changed files with 20255 additions and 403 deletions

19
go.mod
View File

@@ -3,7 +3,7 @@ module github.com/ManyakRus/crud_generator
go 1.22.1
require (
github.com/ManyakRus/starter v1.0.92
github.com/ManyakRus/starter v1.0.210
github.com/alexsergivan/transliterator v1.0.1
github.com/bxcodec/faker/v3 v3.8.1
github.com/davecgh/go-spew v1.1.1
@@ -15,25 +15,26 @@ require (
github.com/ompluscator/dynamic-struct v1.4.0
github.com/otiai10/copy v1.14.0
github.com/serenize/snaker v0.0.0-20201027110005-a7ad2135616e
golang.org/x/tools v0.27.0
golang.org/x/tools v0.29.0
gorm.io/gorm v1.25.12
)
require (
github.com/ManyakRus/logrus v0.0.0-20231019115155-9e6fede0d792 // indirect
github.com/dromara/carbon/v2 v2.6.1 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/pgx/v5 v5.7.1 // indirect
github.com/jackc/pgx/v5 v5.7.2 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/jinzhu/now v1.1.5 // indirect
github.com/joho/godotenv v1.5.1 // indirect
golang.org/x/crypto v0.29.0 // indirect
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.20.0 // indirect
google.golang.org/protobuf v1.35.2 // indirect
golang.org/x/sync v0.11.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect
google.golang.org/protobuf v1.36.4 // indirect
gorm.io/driver/postgres v1.5.11 // indirect
)

25
go.sum
View File

@@ -7,6 +7,12 @@ github.com/ManyakRus/starter v1.0.91 h1:oNQ/jxA2csbsgOuZls0AsXc4uSQpIcfLjnkIqu1Y
github.com/ManyakRus/starter v1.0.91/go.mod h1:ildteZO1poRllhuCistAbG14f/BGjCkCG4dnf5DwfUE=
github.com/ManyakRus/starter v1.0.92 h1:moUliDVEUZbrDJpNSdQ+GT0wjxTjPoas8ZNZ2Hdqfuk=
github.com/ManyakRus/starter v1.0.92/go.mod h1:ildteZO1poRllhuCistAbG14f/BGjCkCG4dnf5DwfUE=
github.com/ManyakRus/starter v1.0.208 h1:uVJ6LzBie8YdxQP4sMsKUftzSTe3G/Oax8YN0i0A+x4=
github.com/ManyakRus/starter v1.0.208/go.mod h1:MTJCd/YbLBnnI3iS6DuVbdunqrLgrOM/os4HzSSyhxA=
github.com/ManyakRus/starter v1.0.209 h1:M4xNkAQADod3tiZhUeJVFu6EzdB1IQhEiwlFJuBlpC8=
github.com/ManyakRus/starter v1.0.209/go.mod h1:MTJCd/YbLBnnI3iS6DuVbdunqrLgrOM/os4HzSSyhxA=
github.com/ManyakRus/starter v1.0.210 h1:v3aU2fY9CQZUr61ekOXxraYvPAwpb0M9iPJnnx1kkAc=
github.com/ManyakRus/starter v1.0.210/go.mod h1:MTJCd/YbLBnnI3iS6DuVbdunqrLgrOM/os4HzSSyhxA=
github.com/alexsergivan/transliterator v1.0.1 h1:vON2ilWCHjq+S5Y4obhLGhHK4Y1VIhsHEtQlij5d9pI=
github.com/alexsergivan/transliterator v1.0.1/go.mod h1:0IrumukulURJ4PD0z6UcdJKP2job1DYDhnHAP5y+5pE=
github.com/bxcodec/faker/v3 v3.8.1 h1:qO/Xq19V6uHt2xujwpaetgKhraGCapqY2CRWGD/SqcM=
@@ -20,6 +26,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/denisenkom/go-mssqldb v0.12.3 h1:pBSGx9Tq67pBOTLmxNuirNTeB8Vjmf886Kx+8Y+8shw=
github.com/denisenkom/go-mssqldb v0.12.3/go.mod h1:k0mtMFOnU+AihqFxPMiF05rtiDrorD1Vrm1KEz5hxDo=
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
github.com/dromara/carbon/v2 v2.6.1 h1:ExZPeH74ApLJ/nqJ+SGp1JSPFawvTDOCG3WSeqYl0mI=
github.com/dromara/carbon/v2 v2.6.1/go.mod h1:Baj3A1uBBctJmpZWJd6/+WWnmIuY2pobR6IOpB6xigc=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
@@ -73,6 +81,8 @@ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7Ulw
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs=
github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA=
github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI=
github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ=
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jimsmart/schema v0.2.1 h1:MsSsqq0i86bUskhJJZ6RnrgscbDeBMalLZym6Hx9l3U=
@@ -150,8 +160,12 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f h1:XdNn9LlyWAhLVp6P/i8QYBW+hlyhrhei9uErw2B5GJo=
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f/go.mod h1:D5SMRVC3C2/4+F/DB1wZsLRnSNimn2Sp/NPsCrsv8ak=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -179,6 +193,7 @@ golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -188,6 +203,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -215,6 +232,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -230,6 +249,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -239,6 +260,8 @@ golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE=
golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -256,6 +279,8 @@ google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=

View File

@@ -86,6 +86,8 @@ func DeleteFuncFromFuncName(Text, FuncName string) string {
Otvet := Text
TextFind := "\nfunc " + FuncName + "("
//TextFind2 := "\nfunc " + FuncName + "("
//pos1 := micro.FindPos(Otvet, TextFind, TextFind2)
pos1 := strings.Index(Otvet, TextFind)
if pos1 < 0 {
return Otvet

View File

@@ -300,7 +300,9 @@ func Replace_ModelStruct(TextTemplateModel, TextModelStruct string) string {
s2 := TextTemplateModel[pos1:]
TextFind1 = "}\n"
posEnd := strings.Index(s2, TextFind1)
TextFind2 := "}\r"
posEnd := micro.FindPos(s2, TextFind1, TextFind2)
//posEnd := strings.Index(s2, TextFind1)
if posEnd < 0 {
log.Panic("Replace_ModelStruct() error: in model.go_ not found text: ", TextFind1)
}

View File

@@ -575,6 +575,8 @@ func FillIDMinimum_ManyPK(MapTable map[string]*types.Table) error {
return err
}
rows.Close()
for i, colName := range ColumnsGorm {
value1 := ""
value1 = fmt.Sprint(*values[i].(*interface{}))

View File

@@ -20,3 +20,9 @@ var CONNECTION_ID int64 = 3 //7
var BRANCH_ID int64 = 2 //20954
var TIME_ZONE = "Europe/Moscow"
// LayoutTime - формат текстового времени для загрузки из json
const LayoutTime = "15:04:05"
// SERVICE_NAME - имя сервиса
const SERVICE_NAME = "starter"

View File

@@ -18,24 +18,26 @@ var CancelContext func()
// onceCtx - гарантирует единственное создание контеста
var onceCtx sync.Once
// lockContextMain - гарантирует единственное создание контеста
// var lockContextMain sync.Mutex
// MutexContextMain - гарантирует единственное создание контеста
var MutexContextMain sync.RWMutex
// GetContext - возвращает глобальный контекст приложения
func GetContext() context.Context {
//lockContextMain.Lock()
//defer lockContextMain.Unlock()
//
MutexContextMain.RLock()
defer MutexContextMain.RUnlock()
//if Ctx == nil {
// CtxBg := context.Background()
// Ctx, CancelContext = context.WithCancel(CtxBg)
//}
onceCtx.Do(func() {
CtxBg := context.Background()
var Ctx0 context.Context
Ctx0, CancelContext = context.WithCancel(CtxBg)
Ctx = &Ctx0
if Ctx == nil { //можно заполнить свой контекст, поэтому if
CtxBg := context.Background()
var Ctx0 context.Context
Ctx0, CancelContext = context.WithCancel(CtxBg)
Ctx = &Ctx0
}
})
return *Ctx
@@ -50,3 +52,17 @@ func GetNewContext() context.Context {
return *Ctx
}
// SetContext - устанавливает глобальный контекст, с учётом Mutex
func SetContext(ctx *context.Context) {
MutexContextMain.Lock()
defer MutexContextMain.Unlock()
Ctx = ctx
}
// SetCancelContext - устанавливает функцию глобального отмены контекста, с учётом Mutex
func SetCancelContext(cancelContext func()) {
MutexContextMain.Lock()
defer MutexContextMain.Unlock()
CancelContext = cancelContext
}

View File

@@ -8,10 +8,13 @@ import (
"encoding/gob"
"errors"
"fmt"
"github.com/ManyakRus/starter/constants"
"github.com/dromara/carbon/v2"
"github.com/google/uuid"
"golang.org/x/exp/constraints"
"google.golang.org/protobuf/types/known/timestamppb"
"hash/fnv"
"math"
"os/exec"
"reflect"
"runtime"
@@ -26,8 +29,16 @@ import (
"time"
)
//// Time - тип для хранения времени
//type Time time.Time
//var log = logger.GetLog()
func init() {
//время всегда московское (из константы)
carbon.SetLocation(constants.Loc)
}
// IsTestApp - возвращает true если это тестовая среда выполнения приложения
func IsTestApp() bool {
Otvet := true
@@ -105,6 +116,20 @@ func Pause_ctx(ctx context.Context, ms int) {
}
}
// Pause_duration - приостановка работы программы на время duration
func Pause_duration(duration time.Duration) {
time.Sleep(duration)
}
// Pause_duration_ctx - приостановка работы программы на время duration, с учётом глобального контекста
func Pause_duration_ctx(ctx context.Context, duration time.Duration) {
select {
case <-ctx.Done():
case <-time.After(duration):
}
}
// FindDirUp - возвращает строку с именем каталога на уровень выше
func FindDirUp(dir string) string {
otvet := dir
@@ -247,7 +272,9 @@ func ProgramDir_Common() string {
//Windows
substr = "\\temp\\"
pos1 = strings.Index(sdir, substr)
if pos1 >= 0 {
substr = "\\tmp\\"
pos2 := strings.Index(sdir, substr)
if pos1 >= 0 || pos2 >= 0 {
filename = CurrentFilename()
dir = filepath.Dir(filename)
@@ -335,36 +362,164 @@ func Trim(s string) string {
return Otvet
}
// Max returns the largest of x or y.
func Max(x, y int) int {
if x < y {
return y
// Max returns the largest value
func Max(Mass ...int) int {
var Otvet int
//
if len(Mass) == 0 {
return Otvet
}
return x
//
Otvet = Mass[0]
for _, val := range Mass {
if val > Otvet {
Otvet = val
}
}
return Otvet
}
// Min returns the smallest of x or y.
func Min(x, y int) int {
if x > y {
return y
// Min returns the smallest value
func Min(Mass ...int) int {
var Otvet int
//
if len(Mass) == 0 {
return Otvet
}
return x
//
Otvet = Mass[0]
for _, val := range Mass {
if val < Otvet {
Otvet = val
}
}
return Otvet
}
// Max returns the largest of x or y.
func MaxInt64(x, y int64) int64 {
if x < y {
return y
// MaxInt64 returns the largest value
func MaxInt64(Mass ...int64) int64 {
var Otvet int64
//
if len(Mass) == 0 {
return Otvet
}
return x
//
Otvet = Mass[0]
for _, val := range Mass {
if val > Otvet {
Otvet = val
}
}
return Otvet
}
// Min returns the smallest of x or y.
func MinInt64(x, y int64) int64 {
if x > y {
return y
// MinInt64 returns the smallest value
func MinInt64(Mass ...int64) int64 {
var Otvet int64
//
if len(Mass) == 0 {
return Otvet
}
return x
//
Otvet = Mass[0]
for _, val := range Mass {
if val < Otvet {
Otvet = val
}
}
return Otvet
}
// MaxInt returns the largest value
func MaxInt(Mass ...int) int {
var Otvet int
//
if len(Mass) == 0 {
return Otvet
}
//
Otvet = Mass[0]
for _, val := range Mass {
if val > Otvet {
Otvet = val
}
}
return Otvet
}
// MinInt returns the smallest value
func MinInt(Mass ...int) int {
var Otvet int
//
if len(Mass) == 0 {
return Otvet
}
//
Otvet = Mass[0]
for _, val := range Mass {
if val < Otvet {
Otvet = val
}
}
return Otvet
}
// MaxFloat64 returns the largest value
func MaxFloat64(Mass ...float64) float64 {
var Otvet float64
//
if len(Mass) == 0 {
return Otvet
}
//
Otvet = Mass[0]
for _, val := range Mass {
if val > Otvet {
Otvet = val
}
}
return Otvet
}
// MinFloat64 returns the smallest value
func MinFloat64(Mass ...float64) float64 {
var Otvet float64
//
if len(Mass) == 0 {
return Otvet
}
//
Otvet = Mass[0]
for _, val := range Mass {
if val < Otvet {
Otvet = val
}
}
return Otvet
}
// MaxDate returns the largest of x or y.
@@ -558,7 +713,7 @@ func CheckINNControlSum12(Inn string) error {
return err
}
// StringFromInt64 - возвращает строку из числа
// StringFromInt64 - возвращает строку из числа int64
func StringFromInt64(i int64) string {
Otvet := ""
@@ -567,6 +722,15 @@ func StringFromInt64(i int64) string {
return Otvet
}
// StringFromInt32 - возвращает строку из числа int32
func StringFromInt32(i int32) string {
Otvet := ""
Otvet = fmt.Sprintf("%d", i)
return Otvet
}
// StringDate - возвращает строку дата без времени
func StringDate(t time.Time) string {
Otvet := ""
@@ -585,7 +749,7 @@ func StringDateTime(t time.Time) string {
return Otvet
}
// ProgramDir_bin - возвращает каталог "bin" или каталог программы
// ProgramDir_bin - возвращает каталог "bin" или каталог программы, в конце "/" (или "\")
func ProgramDir_bin() string {
Otvet := ""
@@ -787,7 +951,12 @@ func StringFromUpperCase(s string) string {
return Otvet
}
Otvet = strings.ToUpper(Otvet[:1]) + Otvet[1:]
//преобразуем в руны т.к. есть русские буквы
MassRunes := []rune(Otvet)
MassRunes[0] = unicode.ToUpper(MassRunes[0])
Otvet = string(MassRunes)
//Otvet = strings.ToUpper(Otvet[:1]) + Otvet[1:]
return Otvet
}
@@ -836,20 +1005,48 @@ func FindLastPos(s, TextFind string) int {
return Otvet
}
// StringFloat64_Dimension2 - возвращает строку с 2 знака после запятой
func StringFloat64_Dimension2(f float64) string {
// StringFromFloat64_Dimension2 - возвращает строку с 2 знака после запятой
func StringFromFloat64_Dimension2(f float64) string {
Otvet := fmt.Sprintf("%.2f", f)
return Otvet
}
// StringFloat32_Dimension2 - возвращает строку с 2 знака после запятой
func StringFloat32_Dimension2(f float32) string {
// StringFromFloat32_Dimension2 - возвращает строку с 2 знака после запятой
func StringFromFloat32_Dimension2(f float32) string {
Otvet := fmt.Sprintf("%.2f", f)
return Otvet
}
// StringFromFloat64_Dimension0 - возвращает строку с 0 знаков после запятой
func StringFromFloat64_Dimension0(f float64) string {
Otvet := fmt.Sprintf("%.0f", f)
return Otvet
}
// StringFromFloat32_Dimension0 - возвращает строку с 0 знаков после запятой
func StringFromFloat32_Dimension0(f float32) string {
Otvet := fmt.Sprintf("%.0f", f)
return Otvet
}
// StringFromFloat64_Dimension - возвращает строку с Dimension знаков после запятой
func StringFromFloat64_Dimension(f float64, Dimension int) string {
Otvet := fmt.Sprintf("%."+strconv.Itoa(Dimension)+"f", f)
return Otvet
}
// StringFromFloat32_Dimension - возвращает строку с Dimension знаков после запятой
func StringFromFloat32_Dimension(f float32, Dimension int) string {
Otvet := fmt.Sprintf("%."+strconv.Itoa(Dimension)+"f", f)
return Otvet
}
// ShowTimePassed - показывает время прошедшее с момента старта
// запускать:
// defer micro.ShowTimePassed(time.Now())
@@ -1362,3 +1559,531 @@ func SetFieldValue(Object any, FieldName string, Value any) error {
return err
}
// Float64FromString - возвращает float64 из строки
func Float64FromString(s string) (float64, error) {
var Otvet float64
var err error
Otvet, err = strconv.ParseFloat(s, 64)
return Otvet, err
}
// Abs - возвращает абсолютное значение
func Abs[T constraints.Integer](x T) T {
if x < 0 {
return -x
}
return x
}
// StringFromBool - возвращает строку из булевского значения
func StringFromBool(value bool) string {
Otvet := "true"
if value == false {
Otvet = "false"
}
return Otvet
}
// StringFromBool_Rus - возвращает строку из булевского значения, Да/Нет
func StringFromBool_Rus(value bool) string {
Otvet := "Да"
if value == false {
Otvet = "Нет"
}
return Otvet
}
// StringFromBool_Rus_lower - возвращает строку из булевского значения, да/нет
func StringFromBool_Rus_lower(value bool) string {
Otvet := "да"
if value == false {
Otvet = "нет"
}
return Otvet
}
//// UnmarshalJSON - преобразует строку время в time.Time
//func (d *Time) UnmarshalJSON(b []byte) error {
// str := string(b)
// if str != "" && str[0] == '"' && str[len(str)-1] == '"' {
// str = str[1 : len(str)-1]
// }
//
// // parse string
// t, err := time.ParseInLocation(constants.LayoutTime, str, constants.Loc)
// if err != nil {
// err = fmt.Errorf("invalid time string: %s, error: %w", b, err)
// return err
// }
//
// //
// *d = Time(t)
// return nil
//}
//// UnmarshalString - преобразует строку время в time.Time
//func (d *Time) UnmarshalString(str string) error {
// if str != "" && str[0] == '"' && str[len(str)-1] == '"' {
// str = str[1 : len(str)-1]
// }
//
// // parse string
// t, err := time.Parse(constants.LayoutTime, str)
// if err != nil {
// err = fmt.Errorf("invalid time string: %s, error: %w", str, err)
// return err
// }
//
// //
// *d = Time(t)
// return nil
//}
// IsFalseString - возвращает true если строка = false, или =0
func IsFalseString(s string) bool {
Otvet := false
s = strings.Trim(s, " ")
s = strings.Trim(s, "\n")
s = strings.ToLower(s)
switch s {
case "0", "нет", "no", "off", "false":
Otvet = true
}
return Otvet
}
// IsTrueString - возвращает true если строка = true, или =1
func IsTrueString(s string) bool {
Otvet := false
s = strings.Trim(s, " ")
s = strings.Trim(s, "\n")
s = strings.ToLower(s)
switch s {
case "1", "да", "yes", "on", "true":
Otvet = true
}
return Otvet
}
// DateTimeFromString_rus - возвращает дату из строки, из формата "02.01.2006 15:04:05"
func DateTimeFromString_rus(s string) (time.Time, error) {
t, err := time.ParseInLocation(constants.LayoutDateTimeRus, s, constants.Loc)
return t, err
}
// DateFromString_rus - возвращает дату из строки, из формата "02.01.2006"
func DateFromString_rus(s string) (time.Time, error) {
//
if len(s) > 10 {
s = s[:10]
}
//
t, err := time.ParseInLocation(constants.LayoutDateRus, s, constants.Loc)
return t, err
}
// DateFromToToday_rus - возвращает дату начала и конца дня
func DateFromToToday_rus() (time.Time, time.Time) {
//carbon.SetLocation(constants.Loc)
Date1 := carbon.Now().StartOfDay().StdTime()
Date2 := carbon.CreateFromStdTime(Date1).EndOfDay().StdTime()
return Date1, Date2
}
// StringDateSPo_rus - возвращает строку с периодом дат
func StringDateSPo_rus(Date1, Date2 time.Time) string {
Otvet := ""
Date1_00 := carbon.CreateFromStdTime(Date1).StartOfDay().StdTime()
Date2_00 := carbon.CreateFromStdTime(Date2).StartOfDay().StdTime()
if Date1_00 == Date2_00 {
Otvet = "на дату: " + StringDate(Date1_00)
} else {
Otvet = fmt.Sprintf("с %s по %s", StringDate(Date1_00), StringDate(Date2_00))
}
return Otvet
}
// StringDatePeriod_rus - возвращает строку с периодом дат
func StringDatePeriod_rus(Date1, Date2 time.Time) string {
Otvet := ""
Date1_00 := carbon.CreateFromStdTime(Date1).StartOfDay().StdTime()
Date2_00 := carbon.CreateFromStdTime(Date2).StartOfDay().StdTime()
if Date1_00 == Date2_00 {
Otvet = "на дату: " + StringDate(Date1_00)
} else {
Otvet = fmt.Sprintf("%s - %s", StringDate(Date1_00), StringDate(Date2_00))
}
return Otvet
}
// StringIntWithSeparator - возвращает строку с разделителем по 3 разрядам
// пример:
// s := StringIntWithSeparator(1222333, '_')
// Ответ: "1_222_333"
func StringIntWithSeparator(n int, separator rune) string {
s := strconv.Itoa(n)
startOffset := 0
var buff bytes.Buffer
if n < 0 {
startOffset = 1
buff.WriteByte('-')
}
l := len(s)
commaIndex := 3 - ((l - startOffset) % 3)
if commaIndex == 3 {
commaIndex = 0
}
for i := startOffset; i < l; i++ {
if commaIndex == 3 {
buff.WriteRune(separator)
commaIndex = 0
}
commaIndex++
buff.WriteByte(s[i])
}
return buff.String()
}
// RoundFloat64 - округляет float64 до precision цифр после запятой
// пример:
// RoundFloat64(123.456, 2) = 123.46
// RoundFloat64(123.456, 1) = 123.5
func RoundFloat64(value float64, precision int) float64 {
ratio := math.Pow(10, float64(precision))
return math.Round(value*ratio) / ratio
}
// StringSplitBylength - разбивает строку на подстроки по n символов, с учётом рун
func StringSplitBylength(s string, n int) []string {
sub := ""
subs := []string{}
//весь текст меньше n
if len(s) <= n {
subs = append(subs, s)
return subs
}
//
runes := bytes.Runes([]byte(s))
l := len(runes)
for i, r := range runes {
sub = sub + string(r)
if (i+1)%n == 0 {
subs = append(subs, sub)
sub = ""
} else if (i + 1) == l {
subs = append(subs, sub)
}
}
return subs
}
// StringSplitBylength_WithLastWord - разбивает строку на подстроки по n символов, с учётом рун
func StringSplitBylength_WithLastWord(s string, n int, LastWord rune) []string {
Otvet := make([]string, 0)
runes := bytes.Runes([]byte(s))
for {
Otvet1, pos1 := stringSplitBylength_WithLastWord1(runes, n, LastWord)
Otvet = append(Otvet, string(Otvet1))
if len(runes) >= pos1 {
runes = runes[pos1:]
} else {
break
}
if len(runes) <= 0 {
break
}
}
return Otvet
}
// stringSplitBylength_WithLastWord1 - возвращает первые n строк, заканчивая на LastWord
func stringSplitBylength_WithLastWord1(s []rune, n int, LastWord rune) ([]rune, int) {
Otvet := make([]rune, 0)
pos1 := 0
runes := s
length1 := len(runes)
length := MinInt(n, length1)
Otvet = runes[:length]
//весь текст меньше n
if len(s) <= n {
return Otvet, len(s)
}
//
for i := length; i > 0; i-- {
if runes[i-1] == LastWord {
pos1 = i
Otvet = Otvet[:pos1]
break
}
}
if pos1 == 0 {
pos1 = len(Otvet)
}
return Otvet, pos1
}
// Round_Float64_WithPrecision округляет float64 до указанного количества знаков после запятой
func Round_Float64_WithPrecision(x float64, precision int) float64 {
pow := math.Pow(10, float64(precision))
Otvet := math.Round(x*pow) / pow
return Otvet
}
// Find_Tag_JSON - возвращает тег json для полей структуры
func Find_Tag_JSON(Struct1 any, FieldName string) (string, error) {
var Otvet string
var err error
field, ok := reflect.TypeOf(Struct1).Elem().FieldByName(FieldName)
if !ok {
err = fmt.Errorf("Field %s not found in type %T", FieldName, Struct1)
return Otvet, err
}
Otvet = field.Tag.Get("json")
return Otvet, err
}
// GetStructValue - возвращает значение 1 поля структуры по его имени
func GetStructValue(Struct1 any, FieldName string) (any, error) {
// Проверяем, что переданный аргумент является структурой
val := reflect.ValueOf(Struct1)
if val.Kind() == reflect.Ptr {
val = val.Elem()
}
if val.Kind() != reflect.Struct {
return nil, errors.New("переданный аргумент не является структурой")
}
// Получаем поле структуры по имени
field := val.FieldByName(FieldName)
if !field.IsValid() {
return nil, errors.New("поле не найдено")
}
// Возвращаем значение поля как interface{}
return field.Interface(), nil
}
// String_DefaultNil - возвращает *string, если пустая строка то nil
func String_DefaultNil(Value string) *string {
var Otvet *string
if Value != "" {
Otvet = &Value
}
return Otvet
}
// Int64_DefaultNil - возвращает *int64, если пустая строка то nil
func Int64_DefaultNil(Value int64) *int64 {
var Otvet *int64
if Value != 0 {
Otvet = &Value
}
return Otvet
}
// Int_DefaultNil - возвращает *int, если значение 0 - возвращает nil
func Int_DefaultNil(Value int) *int {
if Value == 0 {
return nil
}
return &Value
}
// Int8_DefaultNil - возвращает *int8, если значение 0 - возвращает nil
func Int8_DefaultNil(Value int8) *int8 {
if Value == 0 {
return nil
}
return &Value
}
// Int16_DefaultNil - возвращает *int16, если значение 0 - возвращает nil
func Int16_DefaultNil(Value int16) *int16 {
if Value == 0 {
return nil
}
return &Value
}
// Int32_DefaultNil - возвращает *int32, если значение 0 - возвращает nil
func Int32_DefaultNil(Value int32) *int32 {
if Value == 0 {
return nil
}
return &Value
}
// Uint_DefaultNil - возвращает *uint, если значение 0 - возвращает nil
func Uint_DefaultNil(Value uint) *uint {
if Value == 0 {
return nil
}
return &Value
}
// Uint8_DefaultNil - возвращает *uint8, если значение 0 - возвращает nil
func Uint8_DefaultNil(Value uint8) *uint8 {
if Value == 0 {
return nil
}
return &Value
}
// Uint16_DefaultNil - возвращает *uint16, если значение 0 - возвращает nil
func Uint16_DefaultNil(Value uint16) *uint16 {
if Value == 0 {
return nil
}
return &Value
}
// Uint32_DefaultNil - возвращает *uint32, если значение 0 - возвращает nil
func Uint32_DefaultNil(Value uint32) *uint32 {
if Value == 0 {
return nil
}
return &Value
}
// Uint64_DefaultNil - возвращает *uint64, если значение 0 - возвращает nil
func Uint64_DefaultNil(Value uint64) *uint64 {
if Value == 0 {
return nil
}
return &Value
}
// Float32_DefaultNil - возвращает *float32, если значение 0 - возвращает nil
func Float32_DefaultNil(Value float32) *float32 {
if Value == 0 {
return nil
}
return &Value
}
// Float64_DefaultNil - возвращает *float64, если значение 0 - возвращает nil
func Float64_DefaultNil(Value float64) *float64 {
if Value == 0 {
return nil
}
return &Value
}
// Bool_DefaultNil - возвращает *bool, если значение false - возвращает nil
func Bool_DefaultNil(Value bool) *bool {
if !Value {
return nil
}
return &Value
}
// Time_DefaultNil - возвращает *time.Time, если значение IsZero() - возвращает nil
func Time_DefaultNil(Value time.Time) *time.Time {
if Value.IsZero() {
return nil
}
return &Value
}
// IsWindows - возвращает true если операционная система = windows
func IsWindows() bool {
Otvet := false
if runtime.GOOS == "windows" {
Otvet = true
}
return Otvet
}
// Path_Linux_to_Windows - заменяет / на \, для правильных путей файлов
func Path_Linux_to_Windows(s string) string {
Otvet := s
if IsWindows() == true {
Otvet = strings.ReplaceAll(Otvet, `/`, `\`)
}
return Otvet
}
// FindPos - находит наименьший индекс вхождения подстроки
func FindPos(Text string, MassFind ...string) int {
Otvet := -1
PosMin := math.MaxInt
for _, s1 := range MassFind {
pos1 := strings.Index(Text, s1)
if pos1 < PosMin {
PosMin = pos1
}
}
if PosMin != math.MaxInt {
Otvet = PosMin
}
return Otvet
}
// ReadFile_Linux_Windows - читаем файл и удаляет "\r"
func ReadFile_Linux_Windows(Filename string) ([]byte, error) {
MassBytes, err := os.ReadFile(Filename)
if err == nil {
MassBytes = bytes.ReplaceAll(MassBytes, []byte("\r"), []byte(""))
}
return MassBytes, err
}

View File

@@ -15,9 +15,15 @@ import (
// Getenv - возвращает переменную окружения
func Getenv(Name string, IsRequired bool) string {
TextError := "Need fill OS environment variable: "
Otvet := os.Getenv(Name)
if IsRequired == true && Otvet == "" {
log.Error(TextError + Name)
Otvet, IsFind := os.LookupEnv(Name)
if IsFind == true {
return Otvet
}
if IsRequired == true {
log.Panic(TextError + Name)
} else {
log.Warn(TextError + Name)
}
return Otvet
@@ -179,3 +185,52 @@ func Set_FieldFromEnv_Bool(StructReference any, FieldName string, IsRequired boo
return
}
}
// ShowTimePassed - показывает время прошедшее с момента старта
// запускать:
// defer micro.ShowTimePassed(time.Now())
func ShowTimePassed(StartAt time.Time) {
log.Debugf("Time passed: %s\n", time.Since(StartAt))
}
// ShowTimePassed_FormatText - показывает время прошедшее с момента старта
// запускать:
// defer micro.ShowTimePassed(time.Now())
func ShowTimePassed_FormatText(FormatText string, StartAt time.Time) {
log.Debugf(FormatText, time.Since(StartAt))
}
// ShowTimePassedSeconds - показывает время секунд прошедшее с момента старта
// запускать:
// defer micro.ShowTimePassedSeconds(time.Now())
func ShowTimePassedSeconds(StartAt time.Time) {
log.Debugf("Time passed: %s\n", time.Since(StartAt).Round(time.Second))
}
// ShowTimePassedMilliSeconds - показывает время миллисекунд прошедшее с момента старта
// запускать:
// defer micro.ShowTimePassedMilliSeconds(time.Now())
func ShowTimePassedMilliSeconds(StartAt time.Time) {
log.Debugf("Time passed: %s\n", time.Since(StartAt).Round(time.Millisecond))
}
// Set_StructField - устанавливает значение поля из переменной окружения
// Параметры:
// Object - указатель на структуру
// FieldName - имя поля
// Value - значение
func Set_StructField(StructReference any, FieldName string, Value any) {
err := micro.SetFieldValue(StructReference, FieldName, Value)
if err != nil {
err = fmt.Errorf("Set_StructField() FieldName: %s error: %w", FieldName, err)
log.Error(err)
return
}
}
// Show_Stage - показывает в логе переменную окружения STAGE
func Show_Stage() {
Stage := os.Getenv("STAGE")
log.Debugf("STAGE: %s", Stage)
}

View File

@@ -1,13 +1,13 @@
package port_checker
import (
"github.com/ManyakRus/starter/logger"
"github.com/ManyakRus/starter/log"
"net"
"time"
)
// log - глобальный логгер
var log = logger.GetLog()
//var log = logger.GetLog()
// CheckPort_err - проверяет доступность порта, возвращает ошибку
func CheckPort_err(IP, Port string) error {

View File

@@ -7,7 +7,7 @@ import (
"errors"
"fmt"
"github.com/ManyakRus/starter/constants"
"github.com/ManyakRus/starter/logger"
"github.com/ManyakRus/starter/log"
"github.com/ManyakRus/starter/port_checker"
"strings"
"time"
@@ -28,10 +28,13 @@ import (
var Conn *gorm.DB
// log - глобальный логгер
var log = logger.GetLog()
//var log = logger.GetLog()
// mutexReconnect - защита от многопоточности Reconnect()
var mutexReconnect = &sync.Mutex{}
// mutex_Connect - защита от многопоточности Connect()
var mutex_Connect = &sync.RWMutex{}
// mutex_ReConnect - защита от многопоточности ReConnect()
var mutex_ReConnect = &sync.RWMutex{}
// NeedReconnect - флаг необходимости переподключения
var NeedReconnect bool
@@ -170,8 +173,8 @@ func IsClosed() bool {
// Reconnect повторное подключение к базе данных, если оно отключено
// или полная остановка программы
func Reconnect(err error) {
mutexReconnect.Lock()
defer mutexReconnect.Unlock()
mutex_ReConnect.Lock()
defer mutex_ReConnect.Unlock()
if err == nil {
return
@@ -255,17 +258,18 @@ func CloseConnection_err() error {
if err != nil {
log.Error("DB.Close() error: ", err)
}
Conn = nil
//Conn = nil
return err
}
// WaitStop - ожидает отмену глобального контекста
func WaitStop() {
defer stopapp.GetWaitGroup_Main().Done()
select {
case <-contextmain.GetContext().Done():
log.Warn("Context app is canceled. Postgres gorm.")
log.Warn("Context app is canceled. postgres_gorm")
}
//
@@ -274,7 +278,6 @@ func WaitStop() {
//
CloseConnection()
stopapp.GetWaitGroup_Main().Done()
}
// StartDB - делает соединение с БД, отключение и др.
@@ -295,7 +298,10 @@ func Start_ctx(ctx *context.Context, WaitGroup *sync.WaitGroup) error {
var err error
//запомним к себе контекст
contextmain.Ctx = ctx
if contextmain.Ctx != ctx {
contextmain.SetContext(ctx)
}
//contextmain.Ctx = ctx
if ctx == nil {
contextmain.GetContext()
}
@@ -378,7 +384,7 @@ func FillSettings() {
}
if Settings.DB_SCHEMA == "" {
log.Panicln("Need fill DB_SCHEMA ! in os.ENV ")
log.Panicln("Need fill DB_SCHEME ! in os.ENV ")
}
if Settings.DB_USER == "" {
@@ -411,8 +417,18 @@ func GetDSN(ApplicationName string) string {
// GetConnection - возвращает соединение к нужной базе данных
func GetConnection() *gorm.DB {
//мьютекс чтоб не подключаться одновременно
mutex_Connect.RLock()
defer mutex_Connect.RUnlock()
//
if Conn == nil {
Connect()
err := Connect_err()
if err != nil {
log.Error("POSTGRES gorm Connect() to database host: ", Settings.DB_HOST, ", error: ", err)
} else {
log.Info("POSTGRES gorm Connected. host: ", Settings.DB_HOST, ", base name: ", Settings.DB_NAME, ", schema: ", Settings.DB_SCHEMA)
}
}
return Conn
@@ -432,6 +448,8 @@ func GetConnection_WithApplicationName(ApplicationName string) *gorm.DB {
// ping_go - делает пинг каждые 60 секунд, и реконнект
func ping_go() {
//var err error
defer stopapp.GetWaitGroup_Main().Done()
ticker := time.NewTicker(60 * time.Second)
defer ticker.Stop()
@@ -446,8 +464,21 @@ loop:
log.Warn("Context app is canceled. postgres_gorm.ping")
break loop
case <-ticker.C:
err := port_checker.CheckPort_err(Settings.DB_HOST, Settings.DB_PORT)
//log.Debug("ticker, ping err: ", err) //удалить
//ping в базе данных
DB, err := Conn.DB()
if err != nil {
NeedReconnect = true
log.Error("Conn.DB() error: ", err)
} else {
err = DB.PingContext(contextmain.GetContext())
if err != nil {
NeedReconnect = true
log.Error("DB.PingContext() error: ", err)
}
}
//ping порта
err = port_checker.CheckPort_err(Settings.DB_HOST, Settings.DB_PORT)
if err != nil {
NeedReconnect = true
log.Warn("postgres_gorm CheckPort(", addr, ") error: ", err)
@@ -463,7 +494,6 @@ loop:
}
}
stopapp.GetWaitGroup_Main().Done()
}
//// RawMultipleSQL - выполняет текст запроса, отдельно для каждого запроса
@@ -557,6 +587,15 @@ func ReplaceSchema(TextSQL string) string {
return Otvet
}
// ReplaceSchemaName - заменяет имя схемы в тексте SQL
func ReplaceSchemaName(TextSQL, SchemaNameFrom string) string {
Otvet := TextSQL
Otvet = strings.ReplaceAll(Otvet, SchemaNameFrom+".", Settings.DB_SCHEMA+".")
return Otvet
}
// ReplaceTemporaryTableNamesToUnique - заменяет "public.TableName" на "public.TableName_UUID"
func ReplaceTemporaryTableNamesToUnique(TextSQL string) string {
Otvet := TextSQL

View File

@@ -3,7 +3,7 @@
package stopapp
import (
"github.com/ManyakRus/starter/logger"
"github.com/ManyakRus/starter/log"
"os"
"os/signal"
"sync"
@@ -21,7 +21,7 @@ import (
)
// log - глобальный логгер
var log = logger.GetLog()
//var log = logger.GetLog()
// SignalInterrupt - канал для ожидания сигнала остановки приложения
var SignalInterrupt chan os.Signal
@@ -66,6 +66,10 @@ func GetWaitGroup_Main() *sync.WaitGroup {
// StartWaitStop - запускает ожидание сигнала завершения приложения
func StartWaitStop() {
//создадим контекст, т.к. попозже уже гонка данных
contextmain.GetContext()
//
SignalInterrupt = make(chan os.Signal, 1)
fnWait := func() {
@@ -111,7 +115,7 @@ func WaitStop() {
contextmain.CancelContext()
}
case <-contextmain.GetContext().Done():
log.Warn("Context app is canceled.")
log.Warn("Context app is canceled. stopapp")
}
GetWaitGroup_Main().Done()

14
vendor/github.com/dromara/carbon/v2/.editorconfig generated vendored Normal file
View File

@@ -0,0 +1,14 @@
# http://editorconfig.org
root = true
[*]
indent_style = tab
charset = utf-8
trim_trailing_whitespace = true
[*.md]
indent_size = 4
trim_trailing_whitespace = false
[lang/*.json]
indent_size = 4

177
vendor/github.com/dromara/carbon/v2/.golangci.yml generated vendored Normal file
View File

@@ -0,0 +1,177 @@
---
# golangci-lint configuration file made by @ccoVeille
# Source: https://github.com/ccoVeille/golangci-lint-config-examples/
# Author: @ccoVeille
# License: MIT
# Variant: 03-safe
# Version: v1.2.0
#
linters:
# some linters are enabled by default
# https://golangci-lint.run/usage/linters/
#
# enable some extra linters
enable:
# Errcheck is a program for checking for unchecked errors in Go code.
- errcheck
# Linter for Go source code that specializes in simplifying code.
- gosimple
# Vet examines Go source code and reports suspicious constructs.
- govet
# Detects when assignments to existing variables are not used.
- ineffassign
# It's a set of rules from staticcheck. See https://staticcheck.io/
- staticcheck
# Fast, configurable, extensible, flexible, and beautiful linter for Go.
# Drop-in replacement of golint.
- revive
# check imports order and makes it always deterministic.
- gci
# make sure to use t.Helper() when needed
- thelper
# mirror suggests rewrites to avoid unnecessary []byte/string conversion
- mirror
# detect the possibility to use variables/constants from the Go standard library.
- usestdlibvars
# Finds commonly misspelled English words.
- misspell
# Checks for duplicate words in the source code.
- dupword
# linter to detect errors invalid key values count
- loggercheck
# detects nested contexts in loops or function literals
- fatcontext
# Checks usage of github.com/stretchr/testify/require
- testifylint
linters-settings:
gci: # define the section orders for imports
sections:
# Standard section: captures all standard packages.
- standard
# Default section: catchall that is not standard or custom
- default
# linters that related to local tool, so they should be separated
- localmodule
revive:
rules:
# Check for commonly mistaken usages of the sync/atomic package
- name: atomic
# Blank import should be only in a main or test package, or have a comment justifying it.
- name: blank-imports
# Spots comments not starting with a space
- name: comment-spacings
# context.Context() should be the first parameter of a function when provided as argument.
- name: context-as-argument
arguments:
- allowTypesBefore: "*testing.T"
# Basic types should not be used as a key in `context.WithValue`
- name: context-keys-type
# warns on some common mistakes when using defer statement.
- name: defer
# Importing with `.` makes the programs much harder to understand
- name: dot-imports
# suggest to simplify if-then-else constructions when possible
- name: early-return
# Empty blocks make code less readable and could be a symptom of a bug or unfinished refactoring.
- name: empty-block
# for better readability, variables of type `error` must be named with the prefix `err`.
- name: error-naming
# for better readability, the errors should be last in the list of returned values by a function.
- name: error-return
# for better readability, error messages should not be capitalized or end with punctuation or a newline.
- name: error-strings
# report when replacing `errors.New(fmt.Sprintf())` with `fmt.Errorf()` is possible
- name: errorf
# Checking if an error is nil to just after return the error or nil is redundant.
- name: if-return
# incrementing an integer variable by 1 is recommended to be done using the `++` operator
- name: increment-decrement
# highlights redundant else-blocks that can be eliminated from the code
- name: indent-error-flow
# This rule suggests a shorter way of writing ranges that do not use the second value.
- name: range
# receiver names in a method should reflect the struct name (p for Person, for example)
- name: receiver-naming
# redefining built in names (true, false, append, make) can lead to bugs very difficult to detect.
- name: redefines-builtin-id
# redundant else-blocks that can be eliminated from the code.
- name: superfluous-else
# prevent confusing name for variables when using `time` package
- name: time-naming
# warns when an exported function or method returns a value of an un-exported type.
- name: unexported-return
# spots and proposes to remove unreachable code. also helps to spot errors
- name: unreachable-code
# Functions or methods with unused parameters can be a symptom of an unfinished refactoring or a bug.
- name: unused-parameter
# warns on useless break statements in case clauses of switch and select statements
- name: useless-break
# report when a variable declaration can be simplified
- name: var-declaration
# warns when initialism, variable or package naming conventions are not followed.
- name: var-naming
dupword:
# Keywords used to ignore detection.
# Default: []
ignore:
# - "blah" # this will accept "blah blah …" as a valid duplicate word
misspell:
# Correct spellings using locale preferences for US or UK.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
# Default ("") is to use a neutral variety of English.
locale: US
# List of words to ignore
# among the one defined in https://github.com/golangci/misspell/blob/master/words.go
ignore-words:
# - valor
# - and
# Extra word corrections.
extra-words:
# - typo: "whattever"
# correction: "whatever"

21
vendor/github.com/dromara/carbon/v2/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 gouguoyin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

1631
vendor/github.com/dromara/carbon/v2/README.cn.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

1608
vendor/github.com/dromara/carbon/v2/README.jp.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

1607
vendor/github.com/dromara/carbon/v2/README.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

201
vendor/github.com/dromara/carbon/v2/boundary.go generated vendored Normal file
View File

@@ -0,0 +1,201 @@
package carbon
// StartOfCentury returns a Carbon instance for start of the century.
// 本世纪开始时间
func (c *Carbon) StartOfCentury() *Carbon {
if c.IsInvalid() {
return c
}
return create(c.Year()/YearsPerCentury*YearsPerCentury, 1, 1, 0, 0, 0, 0, c.Timezone())
}
// EndOfCentury returns a Carbon instance for end of the century.
// 本世纪结束时间
func (c *Carbon) EndOfCentury() *Carbon {
if c.IsInvalid() {
return c
}
return create(c.Year()/YearsPerCentury*YearsPerCentury+99, 12, 31, 23, 59, 59, 999999999, c.Timezone())
}
// StartOfDecade returns a Carbon instance for start of the decade.
// 本年代开始时间
func (c *Carbon) StartOfDecade() *Carbon {
if c.IsInvalid() {
return c
}
return create(c.Year()/YearsPerDecade*YearsPerDecade, 1, 1, 0, 0, 0, 0, c.Timezone())
}
// EndOfDecade returns a Carbon instance for end of the decade.
// 本年代结束时间
func (c *Carbon) EndOfDecade() *Carbon {
if c.IsInvalid() {
return c
}
return create(c.Year()/YearsPerDecade*YearsPerDecade+9, 12, 31, 23, 59, 59, 999999999, c.Timezone())
}
// StartOfYear returns a Carbon instance for start of the year.
// 本年开始时间
func (c *Carbon) StartOfYear() *Carbon {
if c.IsInvalid() {
return c
}
return create(c.Year(), 1, 1, 0, 0, 0, 0, c.Timezone())
}
// EndOfYear returns a Carbon instance for end of the year.
// 本年结束时间
func (c *Carbon) EndOfYear() *Carbon {
if c.IsInvalid() {
return c
}
return create(c.Year(), 12, 31, 23, 59, 59, 999999999, c.Timezone())
}
// StartOfQuarter returns a Carbon instance for start of the quarter.
// 本季度开始时间
func (c *Carbon) StartOfQuarter() *Carbon {
if c.IsInvalid() {
return c
}
year, quarter, day := c.Year(), c.Quarter(), 1
return create(year, 3*quarter-2, day, 0, 0, 0, 0, c.Timezone())
}
// EndOfQuarter returns a Carbon instance for end of the quarter.
// 本季度结束时间
func (c *Carbon) EndOfQuarter() *Carbon {
if c.IsInvalid() {
return c
}
year, quarter, day := c.Year(), c.Quarter(), 30
switch quarter {
case 1, 4:
day = 31
case 2, 3:
day = 30
}
return create(year, 3*quarter, day, 23, 59, 59, 999999999, c.Timezone())
}
// StartOfMonth returns a Carbon instance for start of the month.
// 本月开始时间
func (c *Carbon) StartOfMonth() *Carbon {
if c.IsInvalid() {
return c
}
year, month, _ := c.Date()
return create(year, month, 1, 0, 0, 0, 0, c.Timezone())
}
// EndOfMonth returns a Carbon instance for end of the month.
// 本月结束时间
func (c *Carbon) EndOfMonth() *Carbon {
if c.IsInvalid() {
return c
}
year, month, _ := c.Date()
return create(year, month+1, 0, 23, 59, 59, 999999999, c.Timezone())
}
// StartOfWeek returns a Carbon instance for start of the week.
// 本周开始时间
func (c *Carbon) StartOfWeek() *Carbon {
if c.IsInvalid() {
return c
}
dayOfWeek, weekStartsAt := c.DayOfWeek(), int(c.weekStartsAt)
return c.SubDays((DaysPerWeek + dayOfWeek - weekStartsAt) % DaysPerWeek).StartOfDay()
}
// EndOfWeek returns a Carbon instance for end of the week.
// 本周结束时间
func (c *Carbon) EndOfWeek() *Carbon {
if c.IsInvalid() {
return c
}
dayOfWeek, weekEndsAt := c.DayOfWeek(), int(c.weekStartsAt)+DaysPerWeek-1
return c.AddDays((DaysPerWeek - dayOfWeek + weekEndsAt) % DaysPerWeek).EndOfDay()
}
// StartOfDay returns a Carbon instance for start of the day.
// 本日开始时间
func (c *Carbon) StartOfDay() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, 0, 0, 0, 0)
}
// EndOfDay returns a Carbon instance for end of the day.
// 本日结束时间
func (c *Carbon) EndOfDay() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, 23, 59, 59, 999999999)
}
// StartOfHour returns a Carbon instance for start of the hour.
// 小时开始时间
func (c *Carbon) StartOfHour() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, c.Hour(), 0, 0, 0)
}
// EndOfHour returns a Carbon instance for end of the hour.
// 小时结束时间
func (c *Carbon) EndOfHour() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, c.Hour(), 59, 59, 999999999)
}
// StartOfMinute returns a Carbon instance for start of the minute.
// 分钟开始时间
func (c *Carbon) StartOfMinute() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, _ := c.DateTime()
return create(year, month, day, hour, minute, 0, 0)
}
// EndOfMinute returns a Carbon instance for end of the minute.
// 分钟结束时间
func (c *Carbon) EndOfMinute() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, _ := c.DateTime()
return create(year, month, day, hour, minute, 59, 999999999)
}
// StartOfSecond returns a Carbon instance for start of the second.
// 秒开始时间
func (c *Carbon) StartOfSecond() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, 0)
}
// EndOfSecond returns a Carbon instance for end of the second.
// 秒结束时间
func (c *Carbon) EndOfSecond() *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, 999999999)
}

72
vendor/github.com/dromara/carbon/v2/calendar.go generated vendored Normal file
View File

@@ -0,0 +1,72 @@
package carbon
import (
"github.com/dromara/carbon/v2/calendar/julian"
"github.com/dromara/carbon/v2/calendar/lunar"
"github.com/dromara/carbon/v2/calendar/persian"
)
// Lunar converts Carbon instance to Lunar instance.
// 将 Carbon 实例转化为 Lunar 实例
func (c *Carbon) Lunar() *lunar.Lunar {
l := new(lunar.Lunar)
if c.IsNil() {
return nil
}
if c.HasError() {
l.Error = c.Error
return l
}
return lunar.FromGregorian(c.StdTime()).ToLunar()
}
// CreateFromLunar creates a Carbon instance from Lunar date and time.
// 从 农历日期 创建 Carbon 实例
func CreateFromLunar(year, month, day, hour, minute, second int, isLeapMonth bool) *Carbon {
l := lunar.FromLunar(year, month, day, hour, minute, second, isLeapMonth)
if !l.IsValid() {
return nil
}
t := lunar.FromLunar(year, month, day, hour, minute, second, isLeapMonth).ToGregorian().Time
return CreateFromStdTime(t)
}
// Julian converts Carbon instance to Julian instance.
// 将 Carbon 实例转化为 Julian 实例
func (c *Carbon) Julian() *julian.Julian {
if c.IsInvalid() {
return nil
}
return julian.FromGregorian(c.StdTime()).ToJulian()
}
// CreateFromJulian creates a Carbon instance from Julian Day or Modified Julian Day.
// 从 儒略日/简化儒略日 创建 Carbon 实例
func CreateFromJulian(f float64) *Carbon {
g := julian.FromJulian(f).ToGregorian()
if !g.IsValid() {
return nil
}
t := julian.FromJulian(f).ToGregorian().Time
return CreateFromStdTime(t)
}
// Persian converts Carbon instance to Persian instance.
// 将 Carbon 实例转化为 Persian 实例
func (c *Carbon) Persian() *persian.Persian {
p := new(persian.Persian)
if c.IsInvalid() {
return p
}
return persian.FromGregorian(c.StdTime()).ToPersian()
}
// CreateFromPersian creates a Carbon instance from Persian date and time.
// 从 波斯日期 创建 Carbon 实例
func CreateFromPersian(year, month, day, hour, minute, second int) *Carbon {
p := persian.FromPersian(year, month, day, hour, minute, second)
if p == nil || p.Error != nil {
return nil
}
return CreateFromStdTime(p.ToGregorian().Time)
}

View File

@@ -0,0 +1,281 @@
// Package calendar is part of the carbon package.
package calendar
import (
"fmt"
"time"
)
var InvalidDateError = func() error {
return fmt.Errorf("invalid gregorian date, please make sure the date is valid")
}
// month constants
// 月份常量
const (
January = "January" // 一月
February = "February" // 二月
March = "March" // 三月
April = "April" // 四月
May = "May" // 五月
June = "June" // 六月
July = "July" // 七月
August = "August" // 八月
September = "September" // 九月
October = "October" // 十月
November = "November" // 十一月
December = "December" // 十二月
)
// week constants
// 星期常量
const (
Monday = "Monday" // 周一
Tuesday = "Tuesday" // 周二
Wednesday = "Wednesday" // 周三
Thursday = "Thursday" // 周四
Friday = "Friday" // 周五
Saturday = "Saturday" // 周六
Sunday = "Sunday" // 周日
)
// number constants
// 数字常量
const (
YearsPerMillennium = 1000 // 每千年1000年
YearsPerCentury = 100 // 每世纪100年
YearsPerDecade = 10 // 每十年10年
QuartersPerYear = 4 // 每年4个季度
MonthsPerYear = 12 // 每年12月
MonthsPerQuarter = 3 // 每季度3月
WeeksPerNormalYear = 52 // 每常规年52周
weeksPerLongYear = 53 // 每长年53周
WeeksPerMonth = 4 // 每月4周
DaysPerLeapYear = 366 // 每闰年366天
DaysPerNormalYear = 365 // 每常规年365天
DaysPerWeek = 7 // 每周7天
HoursPerWeek = 168 // 每周168小时
HoursPerDay = 24 // 每天24小时
MinutesPerDay = 1440 // 每天1440分钟
MinutesPerHour = 60 // 每小时60分钟
SecondsPerWeek = 604800 // 每周604800秒
SecondsPerDay = 86400 // 每天86400秒
SecondsPerHour = 3600 // 每小时3600秒
SecondsPerMinute = 60 // 每分钟60秒
)
// layout constants
// 布局模板常量
const (
AtomLayout = RFC3339Layout
ANSICLayout = time.ANSIC
CookieLayout = "Monday, 02-Jan-2006 15:04:05 MST"
KitchenLayout = time.Kitchen
RssLayout = time.RFC1123Z
RubyDateLayout = time.RubyDate
UnixDateLayout = time.UnixDate
W3cLayout = RFC3339Layout
RFC1036Layout = "Mon, 02 Jan 06 15:04:05 -0700"
RFC1123Layout = time.RFC1123
RFC1123ZLayout = time.RFC1123Z
RFC2822Layout = time.RFC1123Z
RFC3339Layout = "2006-01-02T15:04:05Z07:00"
RFC3339MilliLayout = "2006-01-02T15:04:05.999Z07:00"
RFC3339MicroLayout = "2006-01-02T15:04:05.999999Z07:00"
RFC3339NanoLayout = "2006-01-02T15:04:05.999999999Z07:00"
RFC7231Layout = "Mon, 02 Jan 2006 15:04:05 MST"
RFC822Layout = time.RFC822
RFC822ZLayout = time.RFC822Z
RFC850Layout = time.RFC850
ISO8601Layout = "2006-01-02T15:04:05-07:00"
ISO8601MilliLayout = "2006-01-02T15:04:05.999-07:00"
ISO8601MicroLayout = "2006-01-02T15:04:05.999999-07:00"
ISO8601NanoLayout = "2006-01-02T15:04:05.999999999-07:00"
DayDateTimeLayout = "Mon, Jan 2, 2006 3:04 PM"
DateTimeLayout = "2006-01-02 15:04:05"
DateTimeMilliLayout = "2006-01-02 15:04:05.999"
DateTimeMicroLayout = "2006-01-02 15:04:05.999999"
DateTimeNanoLayout = "2006-01-02 15:04:05.999999999"
ShortDateTimeLayout = "20060102150405"
ShortDateTimeMilliLayout = "20060102150405.999"
ShortDateTimeMicroLayout = "20060102150405.999999"
ShortDateTimeNanoLayout = "20060102150405.999999999"
DateLayout = "2006-01-02"
DateMilliLayout = "2006-01-02.999"
DateMicroLayout = "2006-01-02.999999"
DateNanoLayout = "2006-01-02.999999999"
ShortDateLayout = "20060102"
ShortDateMilliLayout = "20060102.999"
ShortDateMicroLayout = "20060102.999999"
ShortDateNanoLayout = "20060102.999999999"
TimeLayout = "15:04:05"
TimeMilliLayout = "15:04:05.999"
TimeMicroLayout = "15:04:05.999999"
TimeNanoLayout = "15:04:05.999999999"
ShortTimeLayout = "150405"
ShortTimeMilliLayout = "150405.999"
ShortTimeMicroLayout = "150405.999999"
ShortTimeNanoLayout = "150405.999999999"
)
// Gregorian defines a Gregorian struct.
// 定义 Gregorian 结构体
type Gregorian struct {
Time time.Time
Error error
}
// NewGregorian returns a new Gregorian instance.
// 初始化 Gregorian 结构体
func NewGregorian(t time.Time) *Gregorian {
g := new(Gregorian)
if t.IsZero() {
return g
}
g.Time = t
return g
}
// MaxValue returns a Gregorian instance for the greatest supported date.
// 返回 Gregorian 的最大值
func MaxValue() *Gregorian {
return NewGregorian(time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.UTC))
}
// MinValue returns a Gregorian instance for the lowest supported date.
// 返回 Gregorian 的最小值
func MinValue() *Gregorian {
return NewGregorian(time.Date(-9998, 1, 1, 0, 0, 0, 0, time.UTC))
}
// Date gets gregorian year, month, and day like 2020, 8, 5.
// 获取公历年、月、日
func (g *Gregorian) Date() (year, month, day int) {
if g.IsZero() {
return 0, 0, 0
}
var tm time.Month
year, tm, day = g.Time.Date()
month = int(tm)
return
}
// Clock gets gregorian hour, minute, and second like 13, 14, 15.
// 获取公历时、分、秒
func (g *Gregorian) Clock() (hour, minute, second int) {
if g.IsZero() {
return 0, 0, 0
}
return g.Time.Clock()
}
// Year gets gregorian year like 2020.
// 获取公历年
func (g *Gregorian) Year() int {
if g.IsZero() {
return 0
}
return g.Time.Year()
}
// Month gets gregorian month like 8.
// 获取公历月,如 8
func (g *Gregorian) Month() int {
if g.IsZero() {
return 0
}
return int(g.Time.Month())
}
// Week gets gregorian week day like 0.
// 获取周
func (g *Gregorian) Week() int {
if g.IsZero() {
return 0
}
return int(g.Time.Weekday())
}
// Day gets gregorian day like 5.
// 获取公历日,如 0
func (g *Gregorian) Day() int {
if g.IsZero() {
return 0
}
return g.Time.Day()
}
// Hour gets gregorian hour like 13.
// 获取公历小时,如 13
func (g *Gregorian) Hour() int {
if g.IsZero() {
return 0
}
return g.Time.Hour()
}
// Minute gets gregorian minute like 14.
// 获取公历分钟数,如 14
func (g *Gregorian) Minute() int {
if g.IsZero() {
return 0
}
return g.Time.Minute()
}
// Second gets gregorian second like 15.
// 获取公历秒数,如 15
func (g *Gregorian) Second() int {
if g.IsZero() {
return 0
}
return g.Time.Second()
}
// Location gets gregorian timezone information.
// 获取时区信息
func (g *Gregorian) Location() *time.Location {
return g.Time.Location()
}
// String implements Stringer interface and outputs a string in YYYY-MM-DD HH::ii::ss format like "2019-12-07 00:00:00".
// 实现 Stringer 接口, 输出 YYYY-MM-DD HH::ii::ss 格式字符串,如 "2019-12-07 00:00:00"
func (g *Gregorian) String() string {
if g.IsZero() {
return ""
}
return g.Time.Format(DateTimeLayout)
}
// IsZero reports whether is zero time.
// 是否是零值时间
func (g *Gregorian) IsZero() bool {
return g.Time.IsZero()
}
// IsValid reports whether is a valid gregorian date.
// 是否是有效的年份
func (g *Gregorian) IsValid() bool {
if g.Year() >= MinValue().Year() && g.Year() <= MaxValue().Year() && g.Month() >= MinValue().Month() && g.Month() <= MaxValue().Month() && g.Day() >= MinValue().Day() && g.Day() <= MaxValue().Day() {
return true
}
return false
}
// IsLeapYear reports whether is a leap year.
// 是否是闰年
func (g *Gregorian) IsLeapYear() bool {
if g.IsZero() {
return false
}
year := g.Year()
if year%400 == 0 || (year%4 == 0 && year%100 != 0) {
return true
}
return false
}

View File

@@ -0,0 +1,61 @@
# 儒略日/简化儒略日
简体中文 | [English](README.md) | [日本語](README.jp.md)
#### 用法示例
##### 将 `公历` 转换成 `儒略日`
```go
// 默认保留 6 位小数精度
carbon.Parse("2024-01-24 12:00:00").Julian().JD() // 2460334
carbon.Parse("2024-01-24 13:14:15").Julian().JD() // 2460334.051563
// 保留 4 位小数精度
carbon.Parse("2024-01-24 12:00:00").Julian().JD(4) // 2460334
carbon.Parse("2024-01-24 13:14:15").Julian().JD(4) // 2460334.0516
```
##### 将 `公历` 转换成 `简化儒略日`
```go
// 默认保留 6 位小数精度
carbon.Parse("2024-01-24 12:00:00").Julian().MJD() // 60333.5
carbon.Parse("2024-01-24 13:14:15").Julian().MJD() // 60333.551563
// 保留 4 位小数精度
carbon.Parse("2024-01-24 12:00:00").Julian().MJD(4) // 60333.5
carbon.Parse("2024-01-24 13:14:15").Julian().MJD(4) // 60333.5516
```
##### 将 `儒略日` 转换成 `简化儒略日`
```go
// 默认保留 6 位小数精度
carbon.CreateFromJulian(2460334).Julian().MJD() // 60333.5
carbon.CreateFromJulian(2460334.051563).Julian().MJD() // 60332.551563
// 保留 4 位小数精度
carbon.CreateFromJulian(2460334).Julian().MJD(4) // 60333.5
carbon.CreateFromJulian(2460334.051563).Julian().MJD(4) // 60332.5516
```
##### 将 `简化儒略日` 转换成 `儒略日`
```go
// 默认保留 6 位小数精度
carbon.CreateFromJulian(60333.5).Julian().JD()() // 2460334
carbon.CreateFromJulian(60333.551563).Julian().JD()() // 2460333.051563
// 保留 4 位小数精度
carbon.CreateFromJulian(60333.5).Julian().JD(4) // 2460334
carbon.CreateFromJulian(60333.551563).Julian().JD(4) // 2460333.0516
```
##### 将 `儒略日`/`简化儒略日` 转换成 `公历`
```go
// 将 儒略日 转换成 公历
carbon.CreateFromJulian(2460334).ToDateTimeString() // 2024-01-24 12:00:00
carbon.CreateFromJulian(2460334.051563).ToDateTimeString() // 2024-01-24 13:14:15
// 将 简化儒略日 转换成 公历
carbon.CreateFromJulian(60333.5).ToDateTimeString() // 2024-01-24 12:00:00
carbon.CreateFromJulian(60333.551563).ToDateTimeString() // 2024-01-24 13:14:15
```

View File

@@ -0,0 +1,60 @@
# 儒略の日/簡略儒略の日
日本語 | [English](README.md) | [简体中文](README.cn.md)
#### 使い方の例
##### `西暦` を `儒略日` に変換する
```go
// デフォルトの保持 6 ビット小数点精度
carbon.Parse("2024-01-24 12:00:00").Julian().JD() // 2460334
carbon.Parse("2024-01-24 13:14:15").Julian().JD() // 2460334.051563
// 4 ビット小数点精度の保持
carbon.Parse("2024-01-24 12:00:00").Julian().JD(4) // 2460334
carbon.Parse("2024-01-24 13:14:15").Julian().JD(4) // 2460334.0516
```
##### `西暦` を `簡略儒略日` に変換する
```go
// デフォルトの保持 6 ビット小数点精度
carbon.Parse("2024-01-24 12:00:00").Julian().MJD() // 60333.5
carbon.Parse("2024-01-24 13:14:15").Julian().MJD() // 60333.551563
// 4 ビット小数点精度の保持
carbon.Parse("2024-01-24 12:00:00").Julian().MJD(4) // 60333.5
carbon.Parse("2024-01-24 13:14:15").Julian().MJD(4) // 60333.5516
```
##### `儒略日` を `簡略儒略日` に変換する
```go
// デフォルトの保持 6 ビット小数点精度
carbon.CreateFromJulian(2460334).Julian().MJD() // 60333.5
carbon.CreateFromJulian(2460334.051563).Julian().MJD() // 60332.551563
// 4 ビット小数点精度の保持
carbon.CreateFromJulian(2460334).Julian().MJD(4) // 60333.5
carbon.CreateFromJulian(2460334.051563).Julian().MJD(4) // 60332.5516
```
##### `簡略儒略日` を `儒略日` に変換する
```go
// デフォルトの保持 6 ビット小数点精度
carbon.CreateFromJulian(60333.5).Julian().JD()() // 2460334
carbon.CreateFromJulian(60333.551563).Julian().JD()() // 2460333.051563
// 4 ビット小数点精度の保持
carbon.CreateFromJulian(60333.5).Julian().JD(4) // 2460334
carbon.CreateFromJulian(60333.551563).Julian().JD(4) // 2460333.0516
```
##### `儒略日`/`簡略儒略日` を `公历` に変換する
```go
// 儒略日 を 公历 に変換する
carbon.CreateFromJulian(2460334).ToDateTimeString() // 2024-01-24 12:00:00
carbon.CreateFromJulian(2460334.051563).ToDateTimeString() // 2024-01-24 13:14:15
// 簡略儒略日 を 公历 に変換する
carbon.CreateFromJulian(60333.5).ToDateTimeString() // 2024-01-24 12:00:00
carbon.CreateFromJulian(60333.551563).ToDateTimeString() // 2024-01-24 13:14:15
```

View File

@@ -0,0 +1,60 @@
# Julian Day/Modified Julian Day
English | [简体中文](README.cn.md) | [日本語](README.jp.md)
#### Usage and example
##### Convert `Gregorian` calendar to `Julian Day`
```go
// By default, 6 decimal places are retained for precision
carbon.Parse("2024-01-24 12:00:00").Julian().JD() // 2460334
carbon.Parse("2024-01-24 13:14:15").Julian().JD() // 2460334.051563
// 4 decimal places are retained for precision
carbon.Parse("2024-01-24 12:00:00").Julian().JD(4) // 2460334
carbon.Parse("2024-01-24 13:14:15").Julian().JD(4) // 2460334.0516
```
##### Convert `Gregorian` calendar to `Modified Julian Day`
```go
// By default, 6 decimal places are retained for precision
carbon.Parse("2024-01-24 12:00:00").Julian().MJD() // 60333.5
carbon.Parse("2024-01-24 13:14:15").Julian().MJD() // 60333.551563
// 4 decimal places are retained for precision
carbon.Parse("2024-01-24 12:00:00").Julian().MJD(4) // 60333.5
carbon.Parse("2024-01-24 13:14:15").Julian().MJD(4) // 60333.5516
```
##### Convert `Julian Day` to `Modified Julian Day`
```go
// By default, 6 decimal places are retained for precision
carbon.CreateFromJulian(2460334).Julian().MJD() // 60333.5
carbon.CreateFromJulian(2460334.051563).Julian().MJD() // 60332.551563
// 4 decimal places are retained for precision
carbon.CreateFromJulian(2460334).Julian().MJD(4) // 60333.5
carbon.CreateFromJulian(2460334.051563).Julian().MJD(4) // 60332.5516
```
##### Convert `Modified Julian Day` to `Julian Day`
```go
// By default, 6 decimal places are retained for precision
carbon.CreateFromJulian(60333.5).Julian().JD()() // 2460334
carbon.CreateFromJulian(60333.551563).Julian().JD()() // 2460333.051563
// 4 decimal places are retained for precision
carbon.CreateFromJulian(60333.5).Julian().JD(4) // 2460334
carbon.CreateFromJulian(60333.551563).Julian().JD(4) // 2460333.0516
```
##### Convert `Julian Day`/`Modified Julian Day` to `Gregorian` calendar
```go
// Convert Julian Day to Gregorian calendar
carbon.CreateFromJulian(2460334).ToDateTimeString() // 2024-01-24 12:00:00
carbon.CreateFromJulian(2460334.051563).ToDateTimeString() // 2024-01-24 13:14:15
// Convert Modified Julian Day to Gregorian calendar
carbon.CreateFromJulian(60333.5).ToDateTimeString() // 2024-01-24 12:00:00
carbon.CreateFromJulian(60333.551563).ToDateTimeString() // 2024-01-24 13:14:15
```

View File

@@ -0,0 +1,171 @@
// Package julian is part of the carbon package.
package julian
import (
"math"
"strconv"
"time"
"github.com/dromara/carbon/v2/calendar"
)
const (
MinYear = -9997
MaxYear = 9998
)
var (
// julian day or modified julian day decimal precision
// 儒略日或简化儒略日小数精度
decimalPrecision = 6
// difference between Julian Day and Modified Julian Day
// 儒略日和简化儒略日之间的差值
diffJdFromMjd = 2400000.5
)
// Gregorian defines a Gregorian struct.
// 定义 Gregorian 结构体
type Gregorian struct {
calendar.Gregorian
}
// Julian defines a Julian struct.
// 定义 Julian 结构体
type Julian struct {
jd, mjd float64
}
// FromGregorian creates a Gregorian instance from time.Time.
// 从标准 time.Time 创建 Gregorian 实例
func FromGregorian(t time.Time) *Gregorian {
g := new(Gregorian)
g.Time = t
return g
}
// FromJulian creates a Julian instance from julian day or modified julian day.
// 从 儒略日 或 简化儒略日 创建 Julian 实例
func FromJulian(f float64) (j *Julian) {
j = new(Julian)
// get length of the integer part
l := len(strconv.Itoa(int(math.Ceil(f))))
switch l {
// modified julian day
case 5:
j.mjd = f
j.jd = f + diffJdFromMjd
// julian day
case 7:
j.jd = f
j.mjd = f - diffJdFromMjd
default:
j.jd = 0
j.mjd = 0
}
return
}
// ToJulian converts Gregorian instance to Julian instance.
// 将 Gregorian 实例转化为 Julian 实例
func (g *Gregorian) ToJulian() (j *Julian) {
j = new(Julian)
if g == nil {
return nil
}
if g.IsZero() {
j.jd = 1721423.5
j.mjd = -678577
return
}
y := g.Year()
m := g.Month()
d := float64(g.Day()) + ((float64(g.Second())/60+float64(g.Minute()))/60+float64(g.Hour()))/24
n := 0
f := false
if y*372+m*31+int(d) >= 588829 {
f = true
}
if m <= 2 {
m += 12
y--
}
if f {
n = y / 100
n = 2 - n + n/4
}
jd := float64(int(365.25*(float64(y)+4716))) + float64(int(30.6001*(float64(m)+1))) + d + float64(n) - 1524.5
return FromJulian(jd)
}
// ToGregorian converts Julian instance to Gregorian instance.
// 将 Julian 实例转化为 Gregorian 实例
func (j *Julian) ToGregorian() (g *Gregorian) {
g = new(Gregorian)
if g == nil || j.jd == 0 {
return g
}
d := int(j.jd + 0.5)
f := j.jd + 0.5 - float64(d)
if d >= 2299161 {
c := int((float64(d) - 1867216.25) / 36524.25)
d += 1 + c - c/4
}
d += 1524
year := int((float64(d) - 122.1) / 365.25)
d -= int(365.25 * float64(year))
month := int(float64(d) / 30.601)
d -= int(30.601 * float64(month))
day := d
if month > 13 {
month -= 13
year -= 4715
} else {
month -= 1
year -= 4716
}
f *= 24
hour := int(f)
f -= float64(hour)
f *= 60
minute := int(f)
f -= float64(minute)
f *= 60
second := int(math.Round(f))
return FromGregorian(time.Date(year, time.Month(month), day, hour, minute, second, 0, time.Local))
}
// JD gets julian day like 2460332.5
// 获取儒略日
func (j *Julian) JD(precision ...int) float64 {
if j == nil {
return 0
}
p := decimalPrecision
if len(precision) > 0 {
p = precision[0]
}
return parseFloat64(j.jd, p)
}
// MJD gets modified julian day like 60332
// 获取简化儒略日
func (j *Julian) MJD(precision ...int) float64 {
if j == nil {
return 0
}
p := decimalPrecision
if len(precision) > 0 {
p = precision[0]
}
return parseFloat64(j.mjd, p)
}
// parseFloat64 round to n decimal places
// 四舍五入保留 n 位小数点
func parseFloat64(f float64, n int) float64 {
p10 := math.Pow10(n)
return math.Round(f*p10) / p10
}

View File

@@ -0,0 +1,98 @@
# 中国农历
简体中文 | [English](README.md) | [日本語](README.jp.md)
#### 用法示例
> 目前仅支持公元 `1900` 年至 `2100` 年的 `200` 年时间跨度
##### 将 `公历` 转换成 `农历`
```go
// 获取农历生肖
carbon.Parse("2020-08-05 13:14:15").Lunar().Animal() // 鼠
// 获取农历节日
carbon.Parse("2021-02-12 13:14:15").Lunar().Festival() // 春节
// 获取农历年份
carbon.Parse("2020-08-05 13:14:15").Lunar().Year() // 2020
// 获取农历月份
carbon.Parse("2020-08-05 13:14:15").Lunar().Month() // 6
// 获取农历闰月月份
carbon.Parse("2020-08-05 13:14:15").Lunar().LeapMonth() // 4
// 获取农历日期
carbon.Parse("2020-08-05 13:14:15").Lunar().Day() // 16
// 获取农历时辰
carbon.Parse("2020-08-05 13:14:15").Lunar().Hour() // 13
// 获取农历分钟
carbon.Parse("2020-08-05 13:14:15").Lunar().Minute() // 14
// 获取农历秒数
carbon.Parse("2020-08-05 13:14:15").Lunar().Second() // 15
// 获取农历日期时间字符串
carbon.Parse("2020-08-05 13:14:15").Lunar().String() // 2020-06-16 13:14:15
fmt.Printf("%s", carbon.Parse("2020-08-05 13:14:15").Lunar()) // 2020-06-16 13:14:15
// 获取农历年字符串
carbon.Parse("2020-08-05 13:14:15").Lunar().ToYearString() // 二零二零
// 获取农历月字符串
carbon.Parse("2020-08-05 13:14:15").Lunar().ToMonthString() // 六月
// 获取农历闰月字符串
carbon.Parse("2020-04-23 13:14:15").Lunar().ToMonthString() // 闰四月
// 获取农历周字符串
carbon.Parse("2020-04-23 13:14:15").Lunar().ToWeekString() // 周四
// 获取农历天字符串
carbon.Parse("2020-08-05 13:14:15").Lunar().ToDayString() // 十六
// 获取农历日期字符串
carbon.Parse("2020-08-05 13:14:15").Lunar().ToDateString() // 二零二零年六月十六
```
##### 将 `农历` 转化成 `公历`
```go
// 将农历 二零二三年腊月十一 转化为 公历
carbon.CreateFromLunar(2023, 12, 11, 0, 0, 0, false).ToDateTimeString() // 2024-01-21 00:00:00
// 将农历 二零二三年二月十一 转化为 公历
carbon.CreateFromLunar(2023, 2, 11, 0, 0, 0, false).ToDateTimeString() // 2023-03-02 00:00:00
// 将农历 二零二三年闰二月十一 转化为 公历
carbon.CreateFromLunar(2023, 2, 11, 0, 0, 0, true).ToDateTimeString() // 2023-04-01 00:00:00
```
##### 日期判断
```go
// 是否是合法农历日期
carbon.Parse("0000-00-00 00:00:00").Lunar().IsValid() // false
carbon.Parse("2020-08-05 13:14:15").Lunar().IsValid() // true
// 是否是农历闰年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsLeapYear() // true
// 是否是农历闰月
carbon.Parse("2020-08-05 13:14:15").Lunar().IsLeapMonth() // false
// 是否是鼠年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRatYear() // true
// 是否是牛年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsOxYear() // false
// 是否是虎年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsTigerYear() // false
// 是否是兔年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRabbitYear() // false
// 是否是龙年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsDragonYear() // false
// 是否是蛇年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsSnakeYear() // false
// 是否是马年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsHorseYear() // false
// 是否是羊年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsGoatYear() // false
// 是否是猴年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsMonkeyYear() // false
// 是否是鸡年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRoosterYear() // false
// 是否是狗年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsDogYear() // false
// 是否是猪年
carbon.Parse("2020-08-05 13:14:15").Lunar().IsPigYear() // false
```

View File

@@ -0,0 +1,97 @@
# 中国の旧暦
日本語 | [English](README.md) | [简体中文](README.cn.md)
#### 使い方の例
> 現在は西暦` 1900 `年から` 2100 `年までの` 200 `年の時間スパンのみをサポートしている
##### `西暦`を`旧暦`に変換する
```go
// 旧暦の干支を手に入れる
carbon.Parse("2020-08-05 13:14:15").Lunar().Animal() // 鼠
// 旧暦の祝日を取得する
carbon.Parse("2021-02-12 13:14:15").Lunar().Festival() // 春节
// 旧正月の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().Year() // 2020
// 旧暦月の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().Month() // 6
// 旧暦うるう月の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().LeapMonth() // 4
// 旧暦日の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().Day() // 16
// 旧暦時刻の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().Hour() // 13
// 旧暦分の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().Minute() // 14
// 旧暦の取得秒数
carbon.Parse("2020-08-05 13:14:15").Lunar().Second() // 15
// 旧暦日時文字列の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().String() // 2020-06-16 13:14:15
fmt.Printf("%s", carbon.Parse("2020-08-05 13:14:15").Lunar()) // 2020-06-16 13:14:15
// 旧正月文字列の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().ToYearString() // 二零二零
// 旧暦月文字列の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().ToMonthString() // 六月
// 旧暦うるう月文字列の取得
carbon.Parse("2020-04-23 13:14:15").Lunar().ToMonthString() // 闰四月
// 旧暦週文字列の取得
carbon.Parse("2020-04-23 13:14:15").Lunar().ToWeekString() // 周四
// 旧暦日文字列の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().ToDayString() // 十六
// 旧暦日付文字列の取得
carbon.Parse("2020-08-05 13:14:15").Lunar().ToDateString() // 二零二零年六月十六
```
##### `旧暦`を`西暦`に変換する
```go
// 2023 年の旧暦 12 月 11 日をグレゴリオ暦に変換します
carbon.CreateFromLunar(2023, 12, 11, 0, 0, 0, false).ToDateTimeString() // 2024-01-21 00:00:00
// 旧暦の 2023 年 2 月 11 日をグレゴリオ暦に変換します
carbon.CreateFromLunar(2023, 2, 11, 0, 0, 0, false).ToDateTimeString() // 2023-03-02 00:00:00
// 旧暦 2023 年、閏 2 月 11 日をグレゴリオ暦に変換します
carbon.CreateFromLunar(2023, 2, 11, 0, 0, 0, true).ToDateTimeString() // 2023-04-01 00:00:00
```
##### 日付判断
```go
// 合法的なペルシャ暦の日付かどうか
carbon.Parse("0000-00-00 00:00:00").Lunar().IsValid() // false
carbon.Parse("2020-08-05 13:14:15").Lunar().IsValid() // true
// 旧暦うるう年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsLeapYear() // true
// 旧暦うるう月かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsLeapMonth() // false
// ねずみ年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRatYear() // true
// 牛年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsOxYear() // false
// 寅年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsTigerYear() // false
// うさぎ年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRabbitYear() // false
// 龍年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsDragonYear() // false
// 蛇の年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsSnakeYear() // false
// 馬年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsHorseYear() // false
// 羊年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsGoatYear() // false
// 申年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsMonkeyYear() // false
// 鶏の年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRoosterYear() // false
// 犬年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsDogYear() // false
// 豚年かどうか
carbon.Parse("2020-08-05 13:14:15").Lunar().IsPigYear() // false
```

View File

@@ -0,0 +1,97 @@
# Chinese Lunar
English | [简体中文](README.cn.md) | [日本語](README.jp.md)
#### Usage and example
> Currently only `200` years from `1900` to `2100` are supported
##### Convert `Gregorian` calendar to `Lunar` calendar
```go
// Get Lunar year of animal
carbon.Parse("2020-08-05 13:14:15").Lunar().Animal() // 鼠
// Get lunar festival
carbon.Parse("2021-02-12 13:14:15").Lunar().Festival() // 春节
// Get lunar year
carbon.Parse("2020-08-05 13:14:15").Lunar().Year() // 2020
// Get lunar month
carbon.Parse("2020-08-05 13:14:15").Lunar().Month() // 6
// Get lunar leap month
carbon.Parse("2020-08-05 13:14:15").Lunar().LeapMonth() // 4
// Get lunar day
carbon.Parse("2020-08-05 13:14:15").Lunar().Day() // 16
// Get lunar hour
carbon.Parse("2020-08-05 13:14:15").Lunar().Hour() // 13
// Get lunar minute
carbon.Parse("2020-08-05 13:14:15").Lunar().Minute() // 14
// Get lunar second
carbon.Parse("2020-08-05 13:14:15").Lunar().Second() // 15
// Get lunar date and time string
carbon.Parse("2020-08-05 13:14:15").Lunar().String() // 2020-06-16 13:14:15
fmt.Printf("%s", carbon.Parse("2020-08-05 13:14:15").Lunar()) // 2020-06-16 13:14:15
// Get lunar year as string
carbon.Parse("2020-08-05 13:14:15").Lunar().ToYearString() // 二零二零
// Get lunar month as string
carbon.Parse("2020-08-05 13:14:15").Lunar().ToMonthString() // 六月
// Get lunar leap month as string
carbon.Parse("2020-04-23 13:14:15").Lunar().ToMonthString() // 闰四月
// Get lunar week as string
carbon.Parse("2020-04-23 13:14:15").Lunar().ToWeekString() // 周四
// Get lunar day as string
carbon.Parse("2020-08-05 13:14:15").Lunar().ToDayString() // 十六
// Get lunar date as string
carbon.Parse("2020-08-05 13:14:15").Lunar().ToDateString() // 二零二零年六月十六
```
##### Convert `Lunar` calendar to `Gregorian` calendar
```go
// Convert the Lunar Calendar December 11, 2023 to the gregorian calendar
carbon.CreateFromLunar(2023, 12, 11, 0, 0, 0, false).ToDateTimeString() // 2024-01-21 00:00:00
// Convert lunar calendar February 11, 2023 to gregorian calendar
carbon.CreateFromLunar(2023, 2, 11, 0, 0, 0, false).ToDateTimeString() // 2024-03-02 00:00:00
// Convert the Lunar Calendar Leap February 11, 2024 to the gregorian calendar
carbon.CreateFromLunar(2023, 2, 11, 0, 0, 0, true).ToDateTimeString() // 2023-04-01 00:00:00
```
##### Comparison
```go
// Whether is a valid lunar date
carbon.Parse("0000-00-00 00:00:00").Lunar().IsValid() // false
carbon.Parse("2020-08-05 13:14:15").Lunar().IsValid() // true
// Whether is a lunar leap year
carbon.Parse("2020-08-05 13:14:15").Lunar().IsLeapYear() // true
// Whether is a lunar leap month
carbon.Parse("2020-08-05 13:14:15").Lunar().IsLeapMonth() // false
// Whether is a lunar year of the rat
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRatYear() // true
// Whether is a lunar year of the ox
carbon.Parse("2020-08-05 13:14:15").Lunar().IsOxYear() // false
// Whether is a lunar year of the tiger
carbon.Parse("2020-08-05 13:14:15").Lunar().IsTigerYear() // false
// Whether is a lunar year of the rabbit
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRabbitYear() // false
// Whether is a lunar year of the dragon
carbon.Parse("2020-08-05 13:14:15").Lunar().IsDragonYear() // false
// Whether is a lunar year of the snake
carbon.Parse("2020-08-05 13:14:15").Lunar().IsSnakeYear() // false
// Whether is a lunar year of the horse
carbon.Parse("2020-08-05 13:14:15").Lunar().IsHorseYear() // false
// Whether is a lunar year of the goat
carbon.Parse("2020-08-05 13:14:15").Lunar().IsGoatYear() // false
// Whether is a lunar year of the monkey
carbon.Parse("2020-08-05 13:14:15").Lunar().IsMonkeyYear() // false
// Whether is a lunar year of the rooster
carbon.Parse("2020-08-05 13:14:15").Lunar().IsRoosterYear() // false
// Whether is a lunar year of the dog
carbon.Parse("2020-08-05 13:14:15").Lunar().IsDogYear() // false
// Whether is a lunar year of the dig
carbon.Parse("2020-08-05 13:14:15").Lunar().IsPigYear() // false
```

View File

@@ -0,0 +1,590 @@
// Package lunar is part of the carbon package.
package lunar
import (
"fmt"
"strings"
"time"
"github.com/dromara/carbon/v2/calendar"
)
var (
numbers = []string{"零", "一", "二", "三", "四", "五", "六", "七", "八", "九"}
months = []string{"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊"}
weeks = []string{"周日", "周一", "周二", "周三", "周四", "周五", "周六"}
animals = []string{"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"}
festivals = map[string]string{
// "month-day": "name"
"1-1": "春节",
"1-15": "元宵节",
"2-2": "龙抬头",
"3-3": "上巳节",
"5-5": "端午节",
"7-7": "七夕节",
"7-15": "中元节",
"8-15": "中秋节",
"9-9": "重阳节",
"10-1": "寒衣节",
"10-15": "下元节",
"12-8": "腊八节",
}
years = []int{
0x04bd8, 0x04ae0, 0x0a570, 0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2, // 1900-1909
0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0, 0x0ada2, 0x095b0, 0x14977, // 1910-1919
0x04970, 0x0a4b0, 0x0b4b5, 0x06a50, 0x06d40, 0x1ab54, 0x02b60, 0x09570, 0x052f2, 0x04970, // 1920-1929
0x06566, 0x0d4a0, 0x0ea50, 0x16a95, 0x05ad0, 0x02b60, 0x186e3, 0x092e0, 0x1c8d7, 0x0c950, // 1930-1939
0x0d4a0, 0x1d8a6, 0x0b550, 0x056a0, 0x1a5b4, 0x025d0, 0x092d0, 0x0d2b2, 0x0a950, 0x0b557, // 1940-1949
0x06ca0, 0x0b550, 0x15355, 0x04da0, 0x0a5d0, 0x14573, 0x052d0, 0x0a9a8, 0x0e950, 0x06aa0, // 1950-1959
0x0aea6, 0x0ab50, 0x04b60, 0x0aae4, 0x0a570, 0x05260, 0x0f263, 0x0d950, 0x05b57, 0x056a0, // 1960-1969
0x096d0, 0x04dd5, 0x04ad0, 0x0a4d0, 0x0d4d4, 0x0d250, 0x0d558, 0x0b540, 0x0b5a0, 0x195a6, // 1970-1979
0x095b0, 0x049b0, 0x0a974, 0x0a4b0, 0x0b27a, 0x06a50, 0x06d40, 0x0af46, 0x0ab60, 0x09570, // 1980-1989
0x04af5, 0x04970, 0x064b0, 0x074a3, 0x0ea50, 0x06b58, 0x05ac0, 0x0ab60, 0x096d5, 0x092e0, // 1990-1999
0x0c960, 0x0d954, 0x0d4a0, 0x0da50, 0x07552, 0x056a0, 0x0abb7, 0x025d0, 0x092d0, 0x0cab5, // 2000-2009
0x0a950, 0x0b4a0, 0x0baa4, 0x0ad50, 0x055d9, 0x04ba0, 0x0a5b0, 0x15176, 0x052b0, 0x0a930, // 2010-2019
0x07954, 0x06aa0, 0x0ad50, 0x05b52, 0x04b60, 0x0a6e6, 0x0a4e0, 0x0d260, 0x0ea65, 0x0d530, // 2020-2029
0x05aa0, 0x076a3, 0x096d0, 0x04bd7, 0x04ad0, 0x0a4d0, 0x1d0b6, 0x0d250, 0x0d520, 0x0dd45, // 2030-2039
0x0b5a0, 0x056d0, 0x055b2, 0x049b0, 0x0a577, 0x0a4b0, 0x0aa50, 0x1b255, 0x06d20, 0x0ada0, // 2040-2049
0x14b63, 0x09370, 0x049f8, 0x04970, 0x064b0, 0x168a6, 0x0ea50, 0x06b20, 0x1a6c4, 0x0aae0, // 2050-2059
0x0a2e0, 0x0d2e3, 0x0c960, 0x0d557, 0x0d4a0, 0x0da50, 0x05d55, 0x056a0, 0x0a6d0, 0x055d4, // 2060-2069
0x052d0, 0x0a9b8, 0x0a950, 0x0b4a0, 0x0b6a6, 0x0ad50, 0x055a0, 0x0aba4, 0x0a5b0, 0x052b0, // 2070-2079
0x0b273, 0x06930, 0x07337, 0x06aa0, 0x0ad50, 0x14b55, 0x04b60, 0x0a570, 0x054e4, 0x0d160, // 2080-2089
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
0x0d520, // 2100
}
InvalidDateError = func() error {
return fmt.Errorf("invalid invalid date, please make sure the date is valid")
}
)
// Gregorian defines a Gregorian struct.
// 定义 Gregorian 结构体
type Gregorian struct {
calendar.Gregorian
}
// Lunar defines a Lunar struct.
// 定义 Lunar 结构体
type Lunar struct {
year, month, day, hour, minute, second int
isLeapMonth bool
Error error
}
// MaxValue returns a Lunar instance for the greatest supported date.
// 返回 Carbon 的最大值
func MaxValue() *Lunar {
return &Lunar{
year: 2100,
month: 12,
day: 31,
hour: 23,
minute: 59,
second: 59,
}
}
// MinValue returns a Lunar instance for the lowest supported date.
// 返回 Lunar 的最小值
func MinValue() *Lunar {
return &Lunar{
year: 1900,
month: 1,
day: 1,
hour: 0,
minute: 0,
second: 0,
}
}
// FromGregorian creates a Gregorian instance from time.Time.
// 从标准 time.Time 创建 Gregorian 实例
func FromGregorian(t time.Time) *Gregorian {
g := new(Gregorian)
if t.IsZero() {
return g
}
g.Time = t
return g
}
// FromLunar creates a Lunar instance from lunar datetime.
// 从 农历日期 创建 Lunar 实例
func FromLunar(year, month, day, hour, minute, second int, isLeapMonth bool) *Lunar {
l := new(Lunar)
l.year, l.month, l.day = year, month, day
l.hour, l.minute, l.second = hour, minute, second
l.isLeapMonth = isLeapMonth
return l
}
// ToLunar converts Gregorian instance to Lunar instance.
// 将 Gregorian 实例转化为 Lunar 实例
func (g *Gregorian) ToLunar() *Lunar {
l := new(Lunar)
if g.IsZero() {
return l
}
daysInYear, daysInMonth, leapMonth := 365, 30, 0
maxYear, minYear := MaxValue().year, MinValue().year
offset := g.diffInDays(time.Date(minYear, 1, 31, 0, 0, 0, 0, g.Location()))
for l.year = minYear; l.year <= maxYear && offset > 0; l.year++ {
daysInYear = l.getDaysInYear()
offset -= daysInYear
}
if offset < 0 {
offset += daysInYear
l.year--
}
leapMonth = l.LeapMonth()
for l.month = 1; l.month <= 12 && offset > 0; l.month++ {
if leapMonth > 0 && l.month == (leapMonth+1) && !l.isLeapMonth {
l.month--
l.isLeapMonth = true
daysInMonth = l.getDaysInLeapMonth()
} else {
daysInMonth = l.getDaysInMonth()
}
offset -= daysInMonth
if l.isLeapMonth && l.month == (leapMonth+1) {
l.isLeapMonth = false
}
}
// offset为0时,并且刚才计算的月份是闰月,要校正
if offset == 0 && leapMonth > 0 && l.month == leapMonth+1 {
if l.isLeapMonth {
l.isLeapMonth = false
} else {
l.isLeapMonth = true
l.month--
}
}
// offset小于0时,也要校正
if offset < 0 {
offset += daysInMonth
l.month--
}
l.day = offset + 1
l.hour, l.minute, l.second = g.Clock()
if !l.IsValid() {
l.Error = InvalidDateError()
return l
}
return l
}
// ToGregorian converts Lunar instance to Gregorian instance.
// 将 Lunar 实例转化为 Gregorian 实例
func (l *Lunar) ToGregorian() *Gregorian {
g := new(Gregorian)
if !l.IsValid() {
return g
}
days := l.getDaysInMonth()
offset := l.getOffsetInYear()
offset += l.getOffsetInMonth()
// 转换闰月农历 需补充该年闰月的前一个月的时差
if l.isLeapMonth {
offset += days
}
// https://github.com/golang-module/carbon/issues/219
ts := int64(offset+l.day)*86400 - int64(2206512000) + int64(l.hour)*3600 + int64(l.minute)*60 + int64(l.second)
g.Time = time.Unix(ts, 0)
return g
}
// Animal gets lunar animal name like "猴".
// 获取农历生肖
func (l *Lunar) Animal() string {
if !l.IsValid() {
return ""
}
return animals[l.year%calendar.MonthsPerYear]
}
// Festival gets lunar festival name like "春节".
// 获取农历节日
func (l *Lunar) Festival() string {
if !l.IsValid() {
return ""
}
return festivals[fmt.Sprintf("%d-%d", l.month, l.day)]
}
// Year gets lunar year like 2020.
// 获取农历年份
func (l *Lunar) Year() int {
if l.Error != nil {
return 0
}
return l.year
}
// Month gets lunar month like 8.
// 获取农历月份
func (l *Lunar) Month() int {
if l.Error != nil {
return 0
}
return l.month
}
// Day gets lunar day like 5.
// 获取农历日,如 5
func (l *Lunar) Day() int {
if !l.IsValid() {
return 0
}
return l.day
}
// Hour gets current hour like 13.
// 获取农历时辰
func (l *Lunar) Hour() int {
if !l.IsValid() {
return 0
}
return l.hour
}
// Minute gets current minute like 14.
// 获取农历分钟数
func (l *Lunar) Minute() int {
if !l.IsValid() {
return 0
}
return l.minute
}
// Second gets current second like 15.
// 获取农历秒数
func (l *Lunar) Second() int {
if !l.IsValid() {
return 0
}
return l.second
}
// LeapMonth gets lunar leap month like 2.
// 获取农历闰月月份,如 2
func (l *Lunar) LeapMonth() int {
if !l.IsValid() {
return 0
}
minYear := MinValue().year
return years[l.year-minYear] & 0xf
}
// String implements Stringer interface and outputs a string in YYYY-MM-DD HH::ii::ss format like "2019-12-07 00:00:00".
// 实现 Stringer 接口, 输出 YYYY-MM-DD HH::ii::ss 格式字符串,如 "2019-12-07 00:00:00"
func (l *Lunar) String() string {
if !l.IsValid() {
return ""
}
return fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", l.year, l.month, l.day, l.hour, l.minute, l.second)
}
// ToYearString outputs a string in lunar year format like "二零二零".
// 获取农历年份字符串,如 "二零二零"
func (l *Lunar) ToYearString() (year string) {
if !l.IsValid() {
return ""
}
year = fmt.Sprintf("%d", l.year)
for index, number := range numbers {
year = strings.Replace(year, fmt.Sprintf("%d", index), number, -1)
}
return year
}
// ToMonthString outputs a string in lunar month format like "正月".
// 获取农历月份字符串,如 "正月"
func (l *Lunar) ToMonthString() (month string) {
if !l.IsValid() {
return ""
}
month = months[l.month-1] + "月"
if l.IsLeapMonth() {
return "闰" + month
}
return
}
// ToWeekString outputs a string in week layout like "周一".
// 输出完整农历星期字符串,如 "周一"
func (l *Lunar) ToWeekString() (month string) {
if !l.IsValid() {
return ""
}
return weeks[l.ToGregorian().Week()]
}
// ToDayString outputs a string in lunar day format like "廿一".
// 获取农历日字符串,如 "廿一"
func (l *Lunar) ToDayString() (day string) {
if !l.IsValid() {
return ""
}
num := numbers[l.day%10]
switch {
case l.day == 30:
day = "三十"
case l.day > 20:
day = "廿" + num
case l.day == 20:
day = "二十"
case l.day > 10:
day = "十" + num
case l.day == 10:
day = "初十"
case l.day < 10:
day = "初" + num
}
return
}
// ToDateString outputs a string in lunar date format like "二零二零年腊月初五".
// 获取农历日期字符串,如 "二零二零年腊月初五"
func (l *Lunar) ToDateString() string {
if !l.IsValid() {
return ""
}
return l.ToYearString() + "年" + l.ToMonthString() + l.ToDayString()
}
// IsValid reports whether is a valid lunar date.
// 是否是有效的年份
func (l *Lunar) IsValid() bool {
if l == nil || l.Error != nil {
return false
}
if l.Year() >= MinValue().year && l.Year() <= MaxValue().year {
return true
}
return false
}
// IsLeapYear reports whether is a lunar leap year.
// 是否是农历闰年
func (l *Lunar) IsLeapYear() bool {
if !l.IsValid() {
return false
}
return l.LeapMonth() != 0
}
// IsLeapMonth reports whether is a lunar leap month.
// 是否是农历闰月
func (l *Lunar) IsLeapMonth() bool {
if !l.IsValid() {
return false
}
return l.month == l.LeapMonth()
}
// IsRatYear reports whether is lunar year of Rat.
// 是否是鼠年
func (l *Lunar) IsRatYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 4 {
return true
}
return false
}
// IsOxYear reports whether is lunar year of Ox.
// 是否是牛年
func (l *Lunar) IsOxYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 5 {
return true
}
return false
}
// IsTigerYear reports whether is lunar year of Tiger.
// 是否是虎年
func (l *Lunar) IsTigerYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 6 {
return true
}
return false
}
// IsRabbitYear reports whether is lunar year of Rabbit.
// 是否是兔年
func (l *Lunar) IsRabbitYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 7 {
return true
}
return false
}
// IsDragonYear reports whether is lunar year of Dragon.
// 是否是龙年
func (l *Lunar) IsDragonYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 8 {
return true
}
return false
}
// IsSnakeYear reports whether is lunar year of Snake.
// 是否是蛇年
func (l *Lunar) IsSnakeYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 9 {
return true
}
return false
}
// IsHorseYear reports whether is lunar year of Horse.
// 是否是马年
func (l *Lunar) IsHorseYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 10 {
return true
}
return false
}
// IsGoatYear reports whether is lunar year of Goat.
// 是否是羊年
func (l *Lunar) IsGoatYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 11 {
return true
}
return false
}
// IsMonkeyYear reports whether is lunar year of Monkey.
// 是否是猴年
func (l *Lunar) IsMonkeyYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 0 {
return true
}
return false
}
// IsRoosterYear reports whether is lunar year of Rooster.
// 是否是鸡年
func (l *Lunar) IsRoosterYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 1 {
return true
}
return false
}
// IsDogYear reports whether is lunar year of Dog.
// 是否是狗年
func (l *Lunar) IsDogYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 2 {
return true
}
return false
}
// IsPigYear reports whether is lunar year of Pig.
// 是否是猪年
func (l *Lunar) IsPigYear() bool {
if !l.IsValid() {
return false
}
if l.year%calendar.MonthsPerYear == 3 {
return true
}
return false
}
func (g *Gregorian) diffInDays(t time.Time) int {
return int(g.Time.Truncate(time.Hour).Sub(t).Hours() / 24)
}
func (l *Lunar) getOffsetInYear() int {
flag := false
clone, month, offset := *l, 0, 0
for month = 1; month < l.month; month++ {
leapMonth := l.LeapMonth()
if !flag {
// 处理闰月
if leapMonth <= month && leapMonth > 0 {
offset += l.getDaysInLeapMonth()
flag = true
}
}
clone.month = month
offset += clone.getDaysInMonth()
}
return offset
}
func (l *Lunar) getOffsetInMonth() int {
clone, year, offset := *l, 0, 0
for year = MinValue().year; year < l.year; year++ {
clone.year = year
offset += clone.getDaysInYear()
}
return offset
}
func (l *Lunar) getDaysInYear() int {
var days = 348
for i := 0x8000; i > 0x8; i >>= 1 {
if (years[l.year-MinValue().year] & i) != 0 {
days++
}
}
return days + l.getDaysInLeapMonth()
}
func (l *Lunar) getDaysInMonth() int {
if (years[l.year-MinValue().year] & (0x10000 >> uint(l.month))) != 0 {
return 30
}
return 29
}
func (l *Lunar) getDaysInLeapMonth() int {
if l.LeapMonth() == 0 {
return 0
}
if years[l.year-MinValue().year]&0x10000 != 0 {
return 30
}
return 29
}

View File

@@ -0,0 +1,74 @@
# 波斯历(伊朗历)
简体中文 | [English](README.md) | [日本語](README.jp.md)
#### 用法示例
##### 将 `公历` 转换成 `波斯历`
```go
// 获取波斯历年份
carbon.Parse("2020-08-05 13:14:15").Persian().Year() // 1399
// 获取波斯历月份
carbon.Parse("2020-08-05 13:14:15").Persian().Month() // 5
// 获取波斯历日期
carbon.Parse("2020-08-05 13:14:15").Persian().Day() // 15
// 获取波斯历小时
carbon.Parse("2020-08-05 13:14:15").Persian().Hour() // 13
// 获取波斯历分钟
carbon.Parse("2020-08-05 13:14:15").Persian().Minute() // 14
// 获取波斯历秒数
carbon.Parse("2020-08-05 13:14:15").Persian().Second() // 15
// 获取波斯历日期时间字符串
carbon.Parse("2020-08-05 13:14:15").Persian().String() // 1399-05-15 13:14:15
fmt.Printf("%s", carbon.Parse("2020-08-05 13:14:15").Persian()) // 1399-05-15 13:14:15
// 获取波斯历月字符串
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString() // Mordad
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString("en") // Mordad
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString("fa") // مرداد
// 获取简写波斯历月字符串
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString() // Mor
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString("en") // Mor
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString("fa") // مرد
// 获取波斯历周字符串
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString() // Chaharshanbeh
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString("en") // Chaharshanbeh
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString("fa") // چهارشنبه
// 获取简写波斯历周字符串
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString() // Cha
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString("en") // Cha
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString("fa") // د
```
##### 将 `波斯历` 转化成 `公历`
```go
carbon.CreateFromPersian(1, 1, 1, 0, 0, 0).ToDateTimeString() // 2016-03-20 00:00:00
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).ToDateTimeString() // 1243-03-21 00:00:00
carbon.CreateFromPersian(1395, 1, 1, 0, 0, 0).ToDateTimeString() // 2016-03-20 00:00:00
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).ToDateTimeString() // 9998-03-19 00:00:00
```
##### 日期判断
```go
// 是否是合法的波斯历日期
carbon.CreateFromPersian(1, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(0, 0, 0, 0, 0, 0).IsValid() // false
carbon.CreateFromPersian(2024, 0, 1, 0, 0, 0).IsValid() // false
carbon.CreateFromPersian(2024, 1, 0, 0, 0, 0).IsValid() // false
// 是否是波斯历闰年
carbon.CreateFromPersian(1395, 1, 1, 0, 0, 0).IsLeapYear() // true
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).IsLeapYear() // true
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).IsLeapYear() // false
carbon.CreateFromPersian(9999, 1, 1, 0, 0, 0).IsLeapYear() // false
```

View File

@@ -0,0 +1,73 @@
# ペルシア暦(イラン暦)
日本語 | [English](README.md) | [简体中文](README.cn.md)
#### 使い方の例
##### `西暦` を `ペルシャ暦` に変換
```go
// ペルシャ暦の取得
carbon.Parse("2020-08-05 13:14:15").Persian().Year() // 1399
// ペルシャ暦月の取得
carbon.Parse("2020-08-05 13:14:15").Persian().Month() // 5
// ペルシャ暦の取得日
carbon.Parse("2020-08-05 13:14:15").Persian().Day() // 15
// ペルシャ暦時間の取得
carbon.Parse("2020-08-05 13:14:15").Persian().Hour() // 13
// ペルシャ暦分の取得
carbon.Parse("2020-08-05 13:14:15").Persian().Minute() // 14
// ペルシャ暦秒の取得
carbon.Parse("2020-08-05 13:14:15").Persian().Second() // 15
// ペルシャ暦日時文字列の取得
carbon.Parse("2020-08-05 13:14:15").Persian().String() // 1399-05-15 13:14:15
fmt.Printf("%s", carbon.Parse("2020-08-05 13:14:15").Persian()) // 1399-05-15 13:14:15
// ペルシア暦月文字列の取得
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString() // Mordad
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString("en") // Mordad
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString("fa") // مرداد
// 略語ペルシャ暦文字列の取得
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString() // Mor
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString("en") // Mor
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString("fa") // مرد
// ペルシャ暦週文字列の取得
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString() // Chaharshanbeh
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString("en") // Chaharshanbeh
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString("fa") // چهارشنبه
// 略語ペルシャ暦週文字列の取得
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString() // Cha
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString("en") // Cha
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString("fa") // د
```
##### ペルシャ暦を西暦に変換する
```go
carbon.CreateFromPersian(1, 1, 1, 0, 0, 0).ToDateTimeString() // 2016-03-20 00:00:00
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).ToDateTimeString() // 1243-03-21 00:00:00
carbon.CreateFromPersian(1395, 1, 1, 0, 0, 0).ToDateTimeString() // 2016-03-20 00:00:00
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).ToDateTimeString() // 9998-03-19 00:00:00
```
##### 日付判断
```go
// 合法的なペルシャ暦の日付かどうか
carbon.CreateFromPersian(1, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(0, 0, 0, 0, 0, 0).IsValid() // false
carbon.CreateFromPersian(2024, 0, 1, 0, 0, 0).IsValid() // false
carbon.CreateFromPersian(2024, 1, 0, 0, 0, 0).IsValid() // false
// ペルシア暦閏年かどうか
carbon.CreateFromPersian(1395, 1, 1, 0, 0, 0).IsLeapYear() // true
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).IsLeapYear() // true
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).IsLeapYear() // false
carbon.CreateFromPersian(9999, 1, 1, 0, 0, 0).IsLeapYear() // false
```

View File

@@ -0,0 +1,74 @@
# Persian(Jalaali) Calendar
English | [简体中文](README.cn.md) | [日本語](README.jp.md)
#### Usage and example
##### Convert `Gregorian` calendar to `Persian` calendar
```go
// Get persian year
carbon.Parse("2020-08-05 13:14:15").Persian().Year() // 1399
// Get persian month
carbon.Parse("2020-08-05 13:14:15").Persian().Month() // 5
// Get persian day
carbon.Parse("2020-08-05 13:14:15").Persian().Day() // 15
// Get persian hour
carbon.Parse("2020-08-05 13:14:15").Persian().Hour() // 13
// Get persian minute
carbon.Parse("2020-08-05 13:14:15").Persian().Minute() // 14
// Get persian second
carbon.Parse("2020-08-05 13:14:15").Persian().Second() // 15
// Get persian date and time string
carbon.Parse("2020-08-05 13:14:15").Persian().String() // 1399-05-15 13:14:15
fmt.Printf("%s", carbon.Parse("2020-08-05 13:14:15").Persian()) // 1399-05-15 13:14:15
// Get persian month as string
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString() // Mordad
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString("en") // Mordad
carbon.Parse("2020-08-05 13:14:15").Persian().ToMonthString("fa") // مرداد
// Get persian short month as string
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString() // Mor
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString("en") // Mor
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortMonthString("fa") // مرد
// Get persian week as string
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString() // Chaharshanbeh
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString("en") // Chaharshanbeh
carbon.Parse("2020-08-05 13:14:15").Persian().ToWeekString("fa") // چهارشنبه
// Get persian short week as string
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString() // Cha
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString("en") // Cha
carbon.Parse("2020-08-05 13:14:15").Persian().ToShortWeekString("fa") // د
```
##### Convert `Persian` calendar to `Gregorian` calendar
```go
carbon.CreateFromPersian(1, 1, 1, 0, 0, 0).ToDateTimeString() // 2016-03-20 00:00:00
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).ToDateTimeString() // 1243-03-21 00:00:00
carbon.CreateFromPersian(1395, 1, 1, 0, 0, 0).ToDateTimeString() // 2016-03-20 00:00:00
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).ToDateTimeString() // 9998-03-19 00:00:00
```
##### Comparison
```go
// Whether is a valid persian date
carbon.CreateFromPersian(1, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).IsValid() // true
carbon.CreateFromPersian(0, 0, 0, 0, 0, 0).IsValid() // false
carbon.CreateFromPersian(2024, 0, 1, 0, 0, 0).IsValid() // false
carbon.CreateFromPersian(2024, 1, 0, 0, 0, 0).IsValid() // false
// Whether is a persian leap year
carbon.CreateFromPersian(1395, 1, 1, 0, 0, 0).IsLeapYear() // true
carbon.CreateFromPersian(9377, 1, 1, 0, 0, 0).IsLeapYear() // true
carbon.CreateFromPersian(622, 1, 1, 0, 0, 0).IsLeapYear() // false
carbon.CreateFromPersian(9999, 1, 1, 0, 0, 0).IsLeapYear() // false
```

View File

@@ -0,0 +1,325 @@
// Package persian is part of the carbon package.
package persian
import (
"fmt"
"math"
"time"
"github.com/dromara/carbon/v2/calendar"
"github.com/dromara/carbon/v2/calendar/julian"
)
var (
EnMonths = []string{"Farvardin", "Ordibehesht", "Khordad", "Tir", "Mordad", "Shahrivar", "Mehr", "Aban", "Azar", "Dey", "Bahman", "Esfand"}
ShortEnMonths = []string{"Far", "Ord", "Kho", "Tir", "Mor", "Sha", "Meh", "Aba", "Aza", "Dey", "Bah", "Esf"}
FaMonths = []string{"فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"}
ShortFaMonths = []string{"فرو", "ارد", "خرد", "تیر", "مرد", "شهر", "مهر", "آبا", "آذر", "دی", "بهم", "اسف"}
EnWeeks = []string{"Yekshanbeh", "Doshanbeh", "Seshanbeh", "Chaharshanbeh", "Panjshanbeh", "Jomeh", "Shanbeh"}
ShortEnWeeks = []string{"Yek", "Dos", "Ses", "Cha", "Pan", "Jom", "Sha"}
FaWeeks = []string{"نجشنبه", "دوشنبه", "سه شنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه"}
ShortFaWeeks = []string{"پ", "چ", "س", "د", "ی", "ش", "ج"}
InvalidDateError = func() error {
return fmt.Errorf("invalid persian date, please make sure the date is valid")
}
)
// Gregorian defines a Gregorian struct.
// 定义 Gregorian 结构体
type Gregorian struct {
calendar.Gregorian
}
// Persian defines a Persian struct.
// 定义 Persian 结构体
type Persian struct {
year, month, day, hour, minute, second int
Error error
}
// MaxValue returns a Persian instance for the greatest supported date.
// 返回 Persian 的最大值
func MaxValue() *Persian {
return &Persian{
year: 9377,
month: 12,
day: 31,
hour: 23,
minute: 59,
second: 59,
}
}
// MinValue returns a Persian instance for the lowest supported date.
// 返回 Persian 的最小值
func MinValue() *Persian {
return &Persian{
year: 1,
month: 1,
day: 1,
hour: 0,
minute: 0,
second: 0,
}
}
// FromGregorian creates a Gregorian instance from time.Time.
// 从标准 time.Time 创建 Gregorian 实例
func FromGregorian(t time.Time) *Gregorian {
g := new(Gregorian)
if t.IsZero() {
return g
}
g.Time = t
return g
}
// FromPersian creates a Persian instance from persian datetime.
// 从 波斯日期 创建 Persian 实例
func FromPersian(year, month, day, hour, minute, second int) *Persian {
p := new(Persian)
p.year, p.month, p.day = year, month, day
p.hour, p.minute, p.second = hour, minute, second
if !p.IsValid() {
p.Error = InvalidDateError()
return p
}
return p
}
// ToPersian converts Gregorian instance to Persian instance.
// 将 Gregorian 实例转化为 Persian 实例
func (g *Gregorian) ToPersian() *Persian {
p := new(Persian)
p.hour, p.minute, p.second = g.Hour(), g.Minute(), g.Second()
gjdn := getGregorianJdn(g.Year(), g.Month(), g.Day())
pjdn := getPersianJdn(475, 1, 1)
diff := gjdn - pjdn
div := diff / 1029983
mod := diff % 1029983
p.year = (2134*mod/366+2816*(mod%366)+2815)/1028522 + mod/366 + 1 + 2820*div + 474
pjdn = getPersianJdn(p.year, 1, 1)
fjdn := float64(gjdn - pjdn + 1)
if fjdn <= 186 {
p.month = int(math.Ceil(fjdn / 31.0))
} else {
p.month = int(math.Ceil((fjdn - 6) / 30.0))
}
pjdn = getPersianJdn(p.year, p.month, 1)
p.day = gjdn - pjdn + 1
if !p.IsValid() {
p.Error = InvalidDateError()
return p
}
return p
}
// ToGregorian converts Persian instance to Gregorian instance.
// 将 Persian 实例转化为 Gregorian 实例
func (p *Persian) ToGregorian() *Gregorian {
g := new(Gregorian)
if !p.IsValid() {
return g
}
jdn := getPersianJdn(p.year, p.month, p.day)
l := jdn + 68569
n := 4 * l / 146097
l = l - (146097*n+3)/4
i := 4000 * (l + 1) / 1461001
l = l - 1461*i/4 + 31
j := 80 * l / 2447
d := l - 2447*j/80
l = j / 11
m := j + 2 - 12*l
y := 100*(n-49) + i + l
g.Time = time.Date(y, time.Month(m), d, p.hour, p.minute, p.second, 0, time.Local)
return g
}
// Year gets lunar year like 2020.
// 获取年份,如 2020
func (p *Persian) Year() int {
if p.Error != nil {
return 0
}
return p.year
}
// Month gets lunar month like 8.
// 获取月份,如 8
func (p *Persian) Month() int {
if p.Error != nil {
return 0
}
return p.month
}
// Day gets lunar day like 5.
// 获取日,如 5
func (p *Persian) Day() int {
if p.Error != nil {
return 0
}
return p.day
}
// Hour gets current hour like 13.
// 获取小时,如 13
func (p *Persian) Hour() int {
if p.Error != nil {
return 0
}
return p.hour
}
// Minute gets current minute like 14.
// 获取分钟数,如 14
func (p *Persian) Minute() int {
if p.Error != nil {
return 0
}
return p.minute
}
// Second gets current second like 15.
// 获取秒数,如 15
func (p *Persian) Second() int {
if p.Error != nil {
return 0
}
return p.second
}
// String implements Stringer interface and outputs a string in YYYY-MM-DD HH::ii::ss format like "1402-11-11 00:00:00".
// 实现 Stringer 接口, 输出 YYYY-MM-DD HH::ii::ss 格式字符串,如 "1402-11-11 00:00:00"
func (p *Persian) String() string {
if !p.IsValid() {
return ""
}
return fmt.Sprintf("%d-%02d-%02d %02d:%02d:%02d", p.year, p.month, p.day, p.hour, p.minute, p.second)
}
// ToMonthString outputs a string in persian month format like "فروردین".
// 获取完整月份字符串,如 "فروردین"
func (p *Persian) ToMonthString(locale ...string) (month string) {
if !p.IsValid() {
return ""
}
loc := "en"
if len(locale) > 0 {
loc = locale[0]
}
switch loc {
case "en":
return EnMonths[p.month-1]
case "fa":
return FaMonths[p.month-1]
}
return ""
}
// ToShortMonthString outputs a short string in persian month format like "فروردین".
// 获取缩写月份字符串,如 "فروردین"
func (p *Persian) ToShortMonthString(locale ...string) (month string) {
if !p.IsValid() {
return ""
}
loc := "en"
if len(locale) > 0 {
loc = locale[0]
}
switch loc {
case "en":
return ShortEnMonths[p.month-1]
case "fa":
return ShortFaMonths[p.month-1]
}
return ""
}
// ToWeekString outputs a string in week layout like "چهارشنبه".
// 输出完整星期字符串,如 "چهارشنبه"
func (p *Persian) ToWeekString(locale ...string) (month string) {
if !p.IsValid() {
return ""
}
loc := "en"
if len(locale) > 0 {
loc = locale[0]
}
switch loc {
case "en":
return EnWeeks[p.ToGregorian().Week()]
case "fa":
return FaWeeks[p.ToGregorian().Week()]
}
return ""
}
// ToShortWeekString outputs a short string in week layout like "چهارشنبه".
// 输出缩写星期字符串,如 "چهارشنبه"
func (p *Persian) ToShortWeekString(locale ...string) (month string) {
if !p.IsValid() {
return ""
}
loc := "en"
if len(locale) > 0 {
loc = locale[0]
}
switch loc {
case "en":
return ShortEnWeeks[p.ToGregorian().Week()]
case "fa":
return ShortFaWeeks[p.ToGregorian().Week()]
}
return ""
}
// IsValid reports whether is a valid persian date.
// 是否是有效的日期
func (p *Persian) IsValid() bool {
if p.Year() >= MinValue().year && p.Year() <= MaxValue().year && p.month >= MinValue().month && p.month <= MaxValue().month && p.day >= MinValue().day && p.day <= MaxValue().day {
return true
}
return false
}
// IsLeapYear reports whether is a persian leap year.
// 是否是闰年
func (p *Persian) IsLeapYear() bool {
if !p.IsValid() {
return false
}
return (25*p.year+11)%33 < 8
}
// gets Julian day number in Persian calendar
// 获取波斯历儒略日计数
func getPersianJdn(year, month, day int) int {
year = year - 473
if year >= 0 {
year--
}
epy := 474 + (year % 2820)
var md int
if month <= 7 {
md = (month - 1) * 31
} else {
md = (month-1)*30 + 6
}
return day + md + (epy*682-110)/2816 + (epy-1)*365 + year/2820*1029983 + 1948320
}
// gets Julian day number in Gregorian calendar
// 获取公历儒略日计数
func getGregorianJdn(year, month, day int) int {
jdn := julian.FromGregorian(time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)).ToJulian().JD(0)
return int(jdn)
}

58
vendor/github.com/dromara/carbon/v2/carbon.go generated vendored Normal file
View File

@@ -0,0 +1,58 @@
// @Package carbon
// @Description a simple, semantic and developer-friendly time package for golang
// @Page github.com/dromara/carbon
// @Developer gouguoyin
// @Blog www.gouguoyin.com
// @Email 245629560@qq.com
// Package carbon is a simple, semantic and developer-friendly time package for golang.
package carbon
import (
"time"
)
// Carbon defines a Carbon struct.
// 定义 Carbon 结构体
type Carbon struct {
time time.Time
layout string
weekStartsAt time.Weekday
loc *time.Location
lang *Language
Error error
}
// NewCarbon returns a new Carbon instance.
// 返回 Carbon 实例
func NewCarbon(time ...time.Time) *Carbon {
c := &Carbon{lang: NewLanguage()}
c.loc, c.Error = getLocationByTimezone(DefaultTimezone)
if weekday, ok := weekdays[DefaultWeekStartsAt]; ok {
c.weekStartsAt = weekday
}
if len(time) > 0 {
c.time = time[0]
c.loc = time[0].Location()
}
c.layout = DefaultLayout
return c
}
// Copy returns a new copy of the current Carbon instance
// 复制 Carbon 实例
func (c *Carbon) Copy() *Carbon {
newCarbon := NewCarbon()
newCarbon.time = time.Date(c.Year(), time.Month(c.Month()), c.Day(), c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.loc)
newCarbon.layout = c.layout
newCarbon.weekStartsAt = c.weekStartsAt
newCarbon.loc = c.loc
newCarbon.Error = c.Error
newCarbon.lang.dir = c.lang.dir
newCarbon.lang.locale = c.lang.locale
newCarbon.lang.Error = c.lang.Error
return newCarbon
}

565
vendor/github.com/dromara/carbon/v2/comparer.go generated vendored Normal file
View File

@@ -0,0 +1,565 @@
package carbon
import (
"time"
)
// HasError reports whether it has error.
// 是否有错误
func (c *Carbon) HasError() bool {
if c.IsNil() {
return false
}
return c.Error != nil
}
// IsNil reports whether is a nil time.
// 是否是空时间
func (c *Carbon) IsNil() bool {
if c == nil || &c.time == nil {
return true
}
return false
}
// IsZero reports whether is a zero time(0001-01-01 00:00:00 +0000 UTC).
// 是否是零值时间(0001-01-01 00:00:00 +0000 UTC)
func (c *Carbon) IsZero() bool {
if c.IsNil() || c.HasError() {
return false
}
return c.time.IsZero()
}
// IsValid reports whether is a valid time.
// 是否是有效时间
func (c *Carbon) IsValid() bool {
if !c.IsNil() && !c.HasError() {
return true
}
return false
}
// IsInvalid reports whether is an invalid time.
// 是否是无效时间
func (c *Carbon) IsInvalid() bool {
return !c.IsValid()
}
// IsDST reports whether is a daylight saving time.
// 是否是夏令时
func (c *Carbon) IsDST() bool {
if c.IsInvalid() {
return false
}
return c.time.IsDST()
}
// IsAM reports whether is before noon.
// 是否是上午
func (c *Carbon) IsAM() bool {
if c.IsInvalid() {
return false
}
return c.Format("a") == "am"
}
// IsPM reports whether is after noon.
// 是否是下午
func (c *Carbon) IsPM() bool {
if c.IsInvalid() {
return false
}
return c.Format("a") == "pm"
}
// IsLeapYear reports whether is a leap year.
// 是否是闰年
func (c *Carbon) IsLeapYear() bool {
if c.IsInvalid() {
return false
}
year := c.Year()
if year%400 == 0 || (year%4 == 0 && year%100 != 0) {
return true
}
return false
}
// IsLongYear reports whether is a long year, see https://en.wikipedia.org/wiki/ISO_8601#Week_dates.
// 是否是长年
func (c *Carbon) IsLongYear() bool {
if c.IsInvalid() {
return false
}
_, w := time.Date(c.Year(), 12, 31, 0, 0, 0, 0, c.loc).ISOWeek()
return w == weeksPerLongYear
}
// IsJanuary reports whether is January.
// 是否是一月
func (c *Carbon) IsJanuary() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.January)
}
// IsFebruary reports whether is February.
// 是否是二月
func (c *Carbon) IsFebruary() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.February)
}
// IsMarch reports whether is March.
// 是否是三月
func (c *Carbon) IsMarch() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.March)
}
// IsApril reports whether is April.
// 是否是四月
func (c *Carbon) IsApril() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.April)
}
// IsMay reports whether is May.
// 是否是五月
func (c *Carbon) IsMay() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.May)
}
// IsJune reports whether is June.
// 是否是六月
func (c *Carbon) IsJune() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.June)
}
// IsJuly reports whether is July.
// 是否是七月
func (c *Carbon) IsJuly() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.July)
}
// IsAugust reports whether is August.
// 是否是八月
func (c *Carbon) IsAugust() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.August)
}
// IsSeptember reports whether is September.
// 是否是九月
func (c *Carbon) IsSeptember() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.September)
}
// IsOctober reports whether is October.
// 是否是十月
func (c *Carbon) IsOctober() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.October)
}
// IsNovember reports whether is November.
// 是否是十一月
func (c *Carbon) IsNovember() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.November)
}
// IsDecember reports whether is December.
// 是否是十二月
func (c *Carbon) IsDecember() bool {
if c.IsInvalid() {
return false
}
return c.Month() == int(time.December)
}
// IsMonday reports whether is Monday.
// 是否是周一
func (c *Carbon) IsMonday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Monday
}
// IsTuesday reports whether is Tuesday.
// 是否是周二
func (c *Carbon) IsTuesday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Tuesday
}
// IsWednesday reports whether is Wednesday.
// 是否是周三
func (c *Carbon) IsWednesday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Wednesday
}
// IsThursday reports whether is Thursday.
// 是否是周四
func (c *Carbon) IsThursday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Thursday
}
// IsFriday reports whether is Friday.
// 是否是周五
func (c *Carbon) IsFriday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Friday
}
// IsSaturday reports whether is Saturday.
// 是否是周六
func (c *Carbon) IsSaturday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Saturday
}
// IsSunday reports whether is Sunday.
// 是否是周日
func (c *Carbon) IsSunday() bool {
if c.IsInvalid() {
return false
}
return c.StdTime().Weekday() == time.Sunday
}
// IsWeekday reports whether is weekday.
// 是否是工作日
func (c *Carbon) IsWeekday() bool {
if c.IsInvalid() {
return false
}
return !c.IsSaturday() && !c.IsSunday()
}
// IsWeekend reports whether is weekend.
// 是否是周末
func (c *Carbon) IsWeekend() bool {
if c.IsInvalid() {
return false
}
return c.IsSaturday() || c.IsSunday()
}
// IsNow reports whether is now time.
// 是否是当前时间
func (c *Carbon) IsNow() bool {
if c.IsInvalid() {
return false
}
return c.Timestamp() == Now(c.Timezone()).Timestamp()
}
// IsFuture reports whether is future time.
// 是否是未来时间
func (c *Carbon) IsFuture() bool {
if c.IsInvalid() {
return false
}
if c.IsZero() {
return false
}
return c.Timestamp() > Now(c.Timezone()).Timestamp()
}
// IsPast reports whether is past time.
// 是否是过去时间
func (c *Carbon) IsPast() bool {
if c.IsInvalid() {
return false
}
if c.IsZero() {
return true
}
return c.Timestamp() < Now(c.Timezone()).Timestamp()
}
// IsYesterday reports whether is yesterday.
// 是否是昨天
func (c *Carbon) IsYesterday() bool {
if c.IsInvalid() {
return false
}
return c.ToDateString() == Yesterday().ToDateString()
}
// IsToday reports whether is today.
// 是否是今天
func (c *Carbon) IsToday() bool {
if c.IsInvalid() {
return false
}
return c.ToDateString() == Now().ToDateString()
}
// IsTomorrow reports whether is tomorrow.
// 是否是明天
func (c *Carbon) IsTomorrow() bool {
if c.IsInvalid() {
return false
}
return c.ToDateString() == Tomorrow().ToDateString()
}
// IsSameCentury reports whether is same century.
// 是否是同一世纪
func (c *Carbon) IsSameCentury(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return c.Century() == t.Century()
}
// IsSameDecade reports whether is same decade.
// 是否是同一年代
func (c *Carbon) IsSameDecade(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Decade() == t.Decade()
}
// IsSameYear reports whether is same year.
// 是否是同一年
func (c *Carbon) IsSameYear(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Year() == t.Year()
}
// IsSameQuarter reports whether is same quarter.
// 是否是同一季节
func (c *Carbon) IsSameQuarter(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Year() == t.Year() && c.Quarter() == t.Quarter()
}
// IsSameMonth reports whether is same month.
// 是否是同一月
func (c *Carbon) IsSameMonth(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Format("Ym") == t.Format("Ym")
}
// IsSameDay reports whether is same day.
// 是否是同一天
func (c *Carbon) IsSameDay(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Format("Ymd") == t.Format("Ymd")
}
// IsSameHour reports whether is same hour.
// 是否是同一小时
func (c *Carbon) IsSameHour(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Format("YmdH") == t.Format("YmdH")
}
// IsSameMinute reports whether is same minute.
// 是否是同一分钟
func (c *Carbon) IsSameMinute(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Format("YmdHi") == t.Format("YmdHi")
}
// IsSameSecond reports whether is same second.
// 是否是同一秒
func (c *Carbon) IsSameSecond(t *Carbon) bool {
if c.IsInvalid() {
return false
}
return c.Format("YmdHis") == t.Format("YmdHis")
}
// Compare compares by an operator.
// 时间比较
func (c *Carbon) Compare(operator string, t *Carbon) bool {
if c.IsInvalid() {
return false
}
switch operator {
case "=":
return c.Eq(t)
case "<>", "!=":
return !c.Eq(t)
case ">":
return c.Gt(t)
case ">=":
return c.Gte(t)
case "<":
return c.Lt(t)
case "<=":
return c.Lte(t)
}
return false
}
// Gt reports whether greater than.
// 是否大于
func (c *Carbon) Gt(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return c.time.After(t.time)
}
// Lt reports whether less than.
// 是否小于
func (c *Carbon) Lt(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return c.time.Before(t.time)
}
// Eq reports whether equal.
// 是否等于
func (c *Carbon) Eq(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return c.time.Equal(t.time)
}
// Ne reports whether not equal.
// 是否不等于
func (c *Carbon) Ne(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return !c.Eq(t)
}
// Gte reports whether greater than or equal.
// 是否大于等于
func (c *Carbon) Gte(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return c.Gt(t) || c.Eq(t)
}
// Lte reports whether less than or equal.
// 是否小于等于
func (c *Carbon) Lte(t *Carbon) bool {
if c.IsInvalid() || t.IsInvalid() {
return false
}
return c.Lt(t) || c.Eq(t)
}
// Between reports whether between two times, excluded the start and end time.
// 是否在两个时间之间(不包括这两个时间)
func (c *Carbon) Between(start *Carbon, end *Carbon) bool {
if c.IsInvalid() || start.IsInvalid() || end.IsInvalid() {
return false
}
if start.Gt(end) {
return false
}
if c.Gt(start) && c.Lt(end) {
return true
}
return false
}
// BetweenIncludedStart reports whether between two times, included the start time.
// 是否在两个时间之间(包括开始时间)
func (c *Carbon) BetweenIncludedStart(start *Carbon, end *Carbon) bool {
if c.IsInvalid() || start.IsInvalid() || end.IsInvalid() {
return false
}
if start.Gt(end) {
return false
}
if c.Gte(start) && c.Lt(end) {
return true
}
return false
}
// BetweenIncludedEnd reports whether between two times, included the end time.
// 是否在两个时间之间(包括结束时间)
func (c *Carbon) BetweenIncludedEnd(start *Carbon, end *Carbon) bool {
if c.IsInvalid() || start.IsInvalid() || end.IsInvalid() {
return false
}
if start.Gt(end) {
return false
}
if c.Gt(start) && c.Lte(end) {
return true
}
return false
}
// BetweenIncludedBoth reports whether between two times, included the start and end time.
// 是否在两个时间之间(包括这两个时间)
func (c *Carbon) BetweenIncludedBoth(start *Carbon, end *Carbon) bool {
if c.IsInvalid() || start.IsInvalid() || end.IsInvalid() {
return false
}
if start.Gt(end) {
return false
}
if c.Gte(start) && c.Lte(end) {
return true
}
return false
}

288
vendor/github.com/dromara/carbon/v2/constant.go generated vendored Normal file
View File

@@ -0,0 +1,288 @@
package carbon
import (
"time"
)
// Version current version
// 当前版本号
const Version = "2.6.1"
// timezone constants
// 时区常量
const (
Local = "Local" // 本地时间
UTC = "UTC" // 世界协调时间
CET = "CET" // 欧洲中部标准时间
EET = "EET" // 欧洲东部标准时间
EST = "EST" // 美国东部标准时间
GMT = "GMT" // 格林尼治标准时间
MET = "MET" // 欧洲中部标准时间
MST = "MST" // 美国山地标准时间
UCT = "MST" // 世界协调时间
WET = "WET" // 欧洲西部标准时间
Zulu = "Zulu" // 世界协调时间
Cuba = "Cuba" // 古巴
Egypt = "Egypt" // 埃及
Eire = "Eire" // 爱尔兰
Greenwich = "Greenwich" // 格林尼治
Iceland = "Iceland" // 冰岛
Iran = "Iran" // 伊朗
Israel = "Israel" // 以色列
Jamaica = "Jamaica" // 牙买加
Japan = "Japan" // 日本
Libya = "Libya" // 利比亚
Poland = "Poland" // 波兰
Portugal = "Portugal" // 葡萄牙
PRC = "PRC" // 中国
Singapore = "Singapore" // 新加坡
Turkey = "Turkey" // 土耳其
Shanghai = "Asia/Shanghai" // 上海
Chongqing = "Asia/Chongqing" // 重庆
Harbin = "Asia/Harbin" // 哈尔滨
Urumqi = "Asia/Urumqi" // 乌鲁木齐
HongKong = "Asia/Hong_Kong" // 香港
Macao = "Asia/Macao" // 澳门
Taipei = "Asia/Taipei" // 台北
Tokyo = "Asia/Tokyo" // 东京
HoChiMinh = "Asia/Ho_Chi_Minh" // 胡志明
Hanoi = "Asia/Hanoi" // 河内
Saigon = "Asia/Saigon" // 西贡
Seoul = "Asia/Seoul" // 首尔
Pyongyang = "Asia/Pyongyang" // 平壤
Bangkok = "Asia/Bangkok" // 曼谷
Dubai = "Asia/Dubai" // 迪拜
Qatar = "Asia/Qatar" // 卡塔尔
Bangalore = "Asia/Bangalore" // 班加罗尔
Kolkata = "Asia/Kolkata" // 加尔各答
Mumbai = "Asia/Mumbai" // 孟买
MexicoCity = "America/Mexico_City" // 墨西哥
NewYork = "America/New_York" // 纽约
LosAngeles = "America/Los_Angeles" // 洛杉矶
Chicago = "America/Chicago" // 芝加哥
SaoPaulo = "America/Sao_Paulo" // 圣保罗
Moscow = "Europe/Moscow" // 莫斯科
London = "Europe/London" // 伦敦
Berlin = "Europe/Berlin" // 柏林
Paris = "Europe/Paris" // 巴黎
Rome = "Europe/Rome" // 罗马
Sydney = "Australia/Sydney" // 悉尼
Melbourne = "Australia/Melbourne" // 墨尔本
Darwin = "Australia/Darwin" // 达尔文
)
// month constants
// 月份常量
const (
January = "January" // 一月
February = "February" // 二月
March = "March" // 三月
April = "April" // 四月
May = "May" // 五月
June = "June" // 六月
July = "July" // 七月
August = "August" // 八月
September = "September" // 九月
October = "October" // 十月
November = "November" // 十一月
December = "December" // 十二月
)
// constellation constants
// 星座常量
const (
Aries = "Aries" // 白羊座
Taurus = "Taurus" // 金牛座
Gemini = "Gemini" // 双子座
Cancer = "Cancer" // 巨蟹座
Leo = "Leo" // 狮子座
Virgo = "Virgo" // 处女座
Libra = "Libra" // 天秤座
Scorpio = "Scorpio" // 天蝎座
Sagittarius = "Sagittarius" // 射手座
Capricorn = "Capricorn" // 摩羯座
Aquarius = "Aquarius" // 水瓶座
Pisces = "Pisces" // 双鱼座
)
// week constants
// 星期常量
const (
Monday = "Monday" // 周一
Tuesday = "Tuesday" // 周二
Wednesday = "Wednesday" // 周三
Thursday = "Thursday" // 周四
Friday = "Friday" // 周五
Saturday = "Saturday" // 周六
Sunday = "Sunday" // 周日
)
// season constants
// 季节常量
const (
Spring = "Spring" // 春季
Summer = "Summer" // 夏季
Autumn = "Autumn" // 秋季
Winter = "Winter" // 冬季
)
// number constants
// 数字常量
const (
YearsPerMillennium = 1000 // 每千年1000年
YearsPerCentury = 100 // 每世纪100年
YearsPerDecade = 10 // 每十年10年
QuartersPerYear = 4 // 每年4个季度
MonthsPerYear = 12 // 每年12月
MonthsPerQuarter = 3 // 每季度3月
WeeksPerNormalYear = 52 // 每常规年52周
weeksPerLongYear = 53 // 每长年53周
WeeksPerMonth = 4 // 每月4周
DaysPerLeapYear = 366 // 每闰年366天
DaysPerNormalYear = 365 // 每常规年365天
DaysPerWeek = 7 // 每周7天
HoursPerWeek = 168 // 每周168小时
HoursPerDay = 24 // 每天24小时
MinutesPerDay = 1440 // 每天1440分钟
MinutesPerHour = 60 // 每小时60分钟
SecondsPerWeek = 604800 // 每周604800秒
SecondsPerDay = 86400 // 每天86400秒
SecondsPerHour = 3600 // 每小时3600秒
SecondsPerMinute = 60 // 每分钟60秒
)
// layout constants
// 布局模板常量
const (
AtomLayout = RFC3339Layout
ANSICLayout = time.ANSIC
CookieLayout = "Monday, 02-Jan-2006 15:04:05 MST"
KitchenLayout = time.Kitchen
RssLayout = time.RFC1123Z
RubyDateLayout = time.RubyDate
UnixDateLayout = time.UnixDate
W3cLayout = RFC3339Layout
RFC1036Layout = "Mon, 02 Jan 06 15:04:05 -0700"
RFC1123Layout = time.RFC1123
RFC1123ZLayout = time.RFC1123Z
RFC2822Layout = time.RFC1123Z
RFC3339Layout = "2006-01-02T15:04:05Z07:00"
RFC3339MilliLayout = "2006-01-02T15:04:05.999Z07:00"
RFC3339MicroLayout = "2006-01-02T15:04:05.999999Z07:00"
RFC3339NanoLayout = "2006-01-02T15:04:05.999999999Z07:00"
RFC7231Layout = "Mon, 02 Jan 2006 15:04:05 MST"
RFC822Layout = time.RFC822
RFC822ZLayout = time.RFC822Z
RFC850Layout = time.RFC850
ISO8601Layout = "2006-01-02T15:04:05-07:00"
ISO8601MilliLayout = "2006-01-02T15:04:05.999-07:00"
ISO8601MicroLayout = "2006-01-02T15:04:05.999999-07:00"
ISO8601NanoLayout = "2006-01-02T15:04:05.999999999-07:00"
ISO8601ZuluLayout = "2006-01-02T15:04:05Z"
ISO8601ZuluMilliLayout = "2006-01-02T15:04:05.999Z"
ISO8601ZuluMicroLayout = "2006-01-02T15:04:05.999999Z"
ISO8601ZuluNanoLayout = "2006-01-02T15:04:05.999999999Z"
FormattedDateLayout = "Jan 2, 2006"
FormattedDayDateLayout = "Mon, Jan 2, 2006"
DayDateTimeLayout = "Mon, Jan 2, 2006 3:04 PM"
DateTimeLayout = "2006-01-02 15:04:05"
DateTimeMilliLayout = "2006-01-02 15:04:05.999"
DateTimeMicroLayout = "2006-01-02 15:04:05.999999"
DateTimeNanoLayout = "2006-01-02 15:04:05.999999999"
ShortDateTimeLayout = "20060102150405"
ShortDateTimeMilliLayout = "20060102150405.999"
ShortDateTimeMicroLayout = "20060102150405.999999"
ShortDateTimeNanoLayout = "20060102150405.999999999"
DateLayout = "2006-01-02"
DateMilliLayout = "2006-01-02.999"
DateMicroLayout = "2006-01-02.999999"
DateNanoLayout = "2006-01-02.999999999"
ShortDateLayout = "20060102"
ShortDateMilliLayout = "20060102.999"
ShortDateMicroLayout = "20060102.999999"
ShortDateNanoLayout = "20060102.999999999"
TimeLayout = "15:04:05"
TimeMilliLayout = "15:04:05.999"
TimeMicroLayout = "15:04:05.999999"
TimeNanoLayout = "15:04:05.999999999"
ShortTimeLayout = "150405"
ShortTimeMilliLayout = "150405.999"
ShortTimeMicroLayout = "150405.999999"
ShortTimeNanoLayout = "150405.999999999"
)
// format constants
// 格式模板常量
const (
AtomFormat = "Y-m-d\\TH:i:sP"
ANSICFormat = "D M j H:i:s Y"
CookieFormat = "l, d-M-Y H:i:s T"
KitchenFormat = "g:iA"
RssFormat = "D, d M Y H:i:s O"
RubyDateFormat = "D M d H:i:s O Y"
UnixDateFormat = "D M j H:i:s T Y"
RFC1036Format = "D, d M y H:i:s O"
RFC1123Format = "D, d M Y H:i:s T"
RFC1123ZFormat = "D, d M Y H:i:s O"
RFC2822Format = "D, d M Y H:i:s O"
RFC3339Format = "Y-m-d\\TH:i:sP"
RFC3339MilliFormat = "Y-m-d\\TH:i:s.vP"
RFC3339MicroFormat = "Y-m-d\\TH:i:s.uP"
RFC3339NanoFormat = "Y-m-d\\TH:i:s.xP"
RFC7231Format = "D, d M Y H:i:s T"
RFC822Format = "d M y H:i T"
RFC822ZFormat = "d M y H:i O"
RFC850Format = "l, d-M-y H:i:s T"
ISO8601Format = "Y-m-d\\TH:i:sP"
ISO8601MilliFormat = "Y-m-d\\TH:i:s.vP"
ISO8601MicroFormat = "Y-m-d\\TH:i:s.uP"
ISO8601NanoFormat = "Y-m-d\\TH:i:s.xP"
ISO8601ZuluFormat = "Y-m-d\\TH:i:s\\Z"
ISO8601ZuluMilliFormat = "Y-m-d\\TH:i:s.v\\Z"
ISO8601ZuluMicroFormat = "Y-m-d\\TH:i:s.u\\Z"
ISO8601ZuluNanoFormat = "Y-m-d\\TH:i:s.x\\Z"
FormattedDateFormat = "M j, Y"
FormattedDayDateFormat = "D, M j, Y"
DayDateTimeFormat = "D, M j, Y g:i A"
DateTimeFormat = "Y-m-d H:i:s"
DateTimeMilliFormat = "Y-m-d H:i:s.v"
DateTimeMicroFormat = "Y-m-d H:i:s.u"
DateTimeNanoFormat = "Y-m-d H:i:s.x"
ShortDateTimeFormat = "YmdHis"
ShortDateTimeMilliFormat = "YmdHis.v"
ShortDateTimeMicroFormat = "YmdHis.u"
ShortDateTimeNanoFormat = "YmdHis.x"
DateFormat = "Y-m-d"
DateMilliFormat = "Y-m-d.v"
DateMicroFormat = "Y-m-d.u"
DateNanoFormat = "Y-m-d.x"
ShortDateFormat = "Ymd"
ShortDateMilliFormat = "Ymd.v"
ShortDateMicroFormat = "Ymd.u"
ShortDateNanoFormat = "Ymd.x"
TimeFormat = "H:i:s"
TimeMilliFormat = "H:i:s.v"
TimeMicroFormat = "H:i:s.u"
TimeNanoFormat = "H:i:s.x"
ShortTimeFormat = "His"
ShortTimeMilliFormat = "His.v"
ShortTimeMicroFormat = "His.u"
ShortTimeNanoFormat = "His.x"
)

246
vendor/github.com/dromara/carbon/v2/constellation.go generated vendored Normal file
View File

@@ -0,0 +1,246 @@
package carbon
import (
"strings"
)
var constellations = []struct {
startMonth, startDay int
endMonth, endDay int
}{
{3, 21, 4, 19}, // Aries
{4, 20, 5, 20}, // Taurus
{5, 21, 6, 21}, // Gemini
{6, 22, 7, 22}, // Cancer
{7, 23, 8, 22}, // Leo
{8, 23, 9, 22}, // Virgo
{9, 23, 10, 23}, // Libra
{10, 24, 11, 22}, // Scorpio
{11, 23, 12, 21}, // Sagittarius
{12, 22, 1, 19}, // Capricorn
{1, 20, 2, 18}, // Aquarius
{2, 19, 3, 20}, // Pisces
}
// Constellation gets constellation name like "Aries", i18n is supported.
// 获取星座,支持 i18n
func (c *Carbon) Constellation() string {
if c.IsInvalid() {
return ""
}
if len(c.lang.resources) == 0 {
c.lang.SetLocale(DefaultLocale)
}
index := -1
_, month, day := c.Date()
for i := 0; i < len(constellations); i++ {
constellation := constellations[i]
if month == constellation.startMonth && day >= constellation.startDay {
index = i
}
if month == constellation.endMonth && day <= constellation.endDay {
index = i
}
}
c.lang.rw.RLock()
defer c.lang.rw.RUnlock()
if resources, ok := c.lang.resources["constellations"]; ok {
slice := strings.Split(resources, "|")
if len(slice) == MonthsPerYear {
return slice[index]
}
}
return ""
}
// IsAries reports whether is Aries.
// 是否是白羊座
func (c *Carbon) IsAries() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 3 && day >= 21 {
return true
}
if month == 4 && day <= 19 {
return true
}
return false
}
// IsTaurus reports whether is Taurus.
// 是否是金牛座
func (c *Carbon) IsTaurus() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 4 && day >= 20 {
return true
}
if month == 5 && day <= 20 {
return true
}
return false
}
// IsGemini reports whether is Gemini.
// 是否是双子座
func (c *Carbon) IsGemini() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 5 && day >= 21 {
return true
}
if month == 6 && day <= 21 {
return true
}
return false
}
// IsCancer reports whether is Cancer.
// 是否是巨蟹座
func (c *Carbon) IsCancer() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 6 && day >= 22 {
return true
}
if month == 7 && day <= 22 {
return true
}
return false
}
// IsLeo reports whether is Leo.
// 是否是狮子座
func (c *Carbon) IsLeo() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 7 && day >= 23 {
return true
}
if month == 8 && day <= 22 {
return true
}
return false
}
// IsVirgo reports whether is Virgo.
// 是否是处女座
func (c *Carbon) IsVirgo() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 8 && day >= 23 {
return true
}
if month == 9 && day <= 22 {
return true
}
return false
}
// IsLibra reports whether is Libra.
// 是否是天秤座
func (c *Carbon) IsLibra() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 9 && day >= 23 {
return true
}
if month == 10 && day <= 23 {
return true
}
return false
}
// IsScorpio reports whether is Scorpio.
// 是否是天蝎座
func (c *Carbon) IsScorpio() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 10 && day >= 24 {
return true
}
if month == 11 && day <= 22 {
return true
}
return false
}
// IsSagittarius reports whether is Sagittarius.
// 是否是射手座
func (c *Carbon) IsSagittarius() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 11 && day >= 22 {
return true
}
if month == 12 && day <= 21 {
return true
}
return false
}
// IsCapricorn reports whether is Capricorn.
// 是否是摩羯座
func (c *Carbon) IsCapricorn() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 12 && day >= 22 {
return true
}
if month == 1 && day <= 19 {
return true
}
return false
}
// IsAquarius reports whether is Aquarius.
// 是否是水瓶座
func (c *Carbon) IsAquarius() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 1 && day >= 20 {
return true
}
if month == 2 && day <= 18 {
return true
}
return false
}
// IsPisces reports whether is Pisces.
// 是否是双鱼座
func (c *Carbon) IsPisces() bool {
if c.IsInvalid() {
return false
}
_, month, day := c.Date()
if month == 2 && day >= 19 {
return true
}
if month == 3 && day <= 20 {
return true
}
return false
}

161
vendor/github.com/dromara/carbon/v2/creator.go generated vendored Normal file
View File

@@ -0,0 +1,161 @@
package carbon
import (
"time"
)
// CreateFromStdTime creates a Carbon instance from standard time.Time.
// 从标准的 time.Time 创建 Carbon 实例
func CreateFromStdTime(tt time.Time, timezone ...string) *Carbon {
c := NewCarbon(tt)
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
return c
}
// CreateFromTimestamp creates a Carbon instance from a given timestamp with second.
// 从给定的秒级时间戳创建 Carbon 实例
func CreateFromTimestamp(timestamp int64, timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
c.time = time.Unix(timestamp, 0)
return c
}
// CreateFromTimestampMilli creates a Carbon instance from a given timestamp with millisecond.
// 从给定的毫秒级时间戳创建 Carbon 实例
func CreateFromTimestampMilli(timestamp int64, timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
c.time = time.Unix(timestamp/1e3, (timestamp%1e3)*1e6)
return c
}
// CreateFromTimestampMicro creates a Carbon instance from a given timestamp with microsecond.
// 从给定的微秒级时间戳创建 Carbon 实例
func CreateFromTimestampMicro(timestamp int64, timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
c.time = time.Unix(timestamp/1e6, (timestamp%1e6)*1e3)
return c
}
// CreateFromTimestampNano creates a Carbon instance from a given timestamp with nanosecond.
// 从给定的纳秒级时间戳创建 Carbon 实例
func CreateFromTimestampNano(timestamp int64, timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
c.time = time.Unix(timestamp/1e9, timestamp%1e9)
return c
}
// CreateFromDateTime creates a Carbon instance from a given date and time.
// 从给定的年、月、日、时、分、秒创建 Carbon 实例
func CreateFromDateTime(year, month, day, hour, minute, second int, timezone ...string) *Carbon {
return create(year, month, day, hour, minute, second, 0, timezone...)
}
// CreateFromDateTimeMilli creates a Carbon instance from a given date, time and millisecond.
// 从给定的年、月、日、时、分、秒、毫秒创建 Carbon 实例
func CreateFromDateTimeMilli(year, month, day, hour, minute, second, millisecond int, timezone ...string) *Carbon {
return create(year, month, day, hour, minute, second, millisecond*1e6, timezone...)
}
// CreateFromDateTimeMicro creates a Carbon instance from a given date, time and microsecond.
// 从给定的年、月、日、时、分、秒、微秒创建 Carbon 实例
func CreateFromDateTimeMicro(year, month, day, hour, minute, second, microsecond int, timezone ...string) *Carbon {
return create(year, month, day, hour, minute, second, microsecond*1e3, timezone...)
}
// CreateFromDateTimeNano creates a Carbon instance from a given date, time and nanosecond.
// 从给定的年、月、日、时、分、秒、纳秒创建 Carbon 实例
func CreateFromDateTimeNano(year, month, day, hour, minute, second, nanosecond int, timezone ...string) *Carbon {
return create(year, month, day, hour, minute, second, nanosecond, timezone...)
}
// CreateFromDate creates a Carbon instance from a given date.
// 从给定的年、月、日创建 Carbon 实例
func CreateFromDate(year, month, day int, timezone ...string) *Carbon {
return create(year, month, day, 0, 0, 0, 0, timezone...)
}
// CreateFromDateMilli creates a Carbon instance from a given date and millisecond.
// 从给定的年、月、日、毫秒创建 Carbon 实例
func CreateFromDateMilli(year, month, day, millisecond int, timezone ...string) *Carbon {
return create(year, month, day, 0, 0, 0, millisecond*1e6, timezone...)
}
// CreateFromDateMicro creates a Carbon instance from a given date and microsecond.
// 从给定的年、月、日、微秒创建 Carbon 实例
func CreateFromDateMicro(year, month, day, microsecond int, timezone ...string) *Carbon {
return create(year, month, day, 0, 0, 0, microsecond*1e3, timezone...)
}
// CreateFromDateNano creates a Carbon instance from a given date and nanosecond.
// 从给定的年、月、日、纳秒创建 Carbon 实例
func CreateFromDateNano(year, month, day, nanosecond int, timezone ...string) *Carbon {
return create(year, month, day, 0, 0, 0, nanosecond, timezone...)
}
// CreateFromTime creates a Carbon instance from a given time(year, month and day are taken from the current time).
// 从给定的时、分、秒创建 Carbon 实例(年、月、日取自当前时间)
func CreateFromTime(hour, minute, second int, timezone ...string) *Carbon {
year, month, day := Now(timezone...).Date()
return create(year, month, day, hour, minute, second, 0, timezone...)
}
// CreateFromTimeMilli creates a Carbon instance from a given time and millisecond(year, month and day are taken from the current time).
// 从给定的时、分、秒、毫秒创建 Carbon 实例(年、月、日取自当前时间)
func CreateFromTimeMilli(hour, minute, second, millisecond int, timezone ...string) *Carbon {
year, month, day := Now(timezone...).Date()
return create(year, month, day, hour, minute, second, millisecond*1e6, timezone...)
}
// CreateFromTimeMicro creates a Carbon instance from a given time and microsecond(year, month and day are taken from the current time).
// 从给定的时、分、秒、微秒创建 Carbon 实例(年、月、日取自当前时间)
func CreateFromTimeMicro(hour, minute, second, microsecond int, timezone ...string) *Carbon {
year, month, day := Now(timezone...).Date()
return create(year, month, day, hour, minute, second, microsecond*1e3, timezone...)
}
// CreateFromTimeNano creates a Carbon instance from a given time and nanosecond(year, month and day are taken from the current time).
// 从给定的时、分、秒、纳秒创建 Carbon 实例(年、月、日取自当前时间)
func CreateFromTimeNano(hour, minute, second, nanosecond int, timezone ...string) *Carbon {
year, month, day := Now(timezone...).Date()
return create(year, month, day, hour, minute, second, nanosecond, timezone...)
}
// creates a Carbon instance from a given date, time and nanosecond.
// 从给定的年、月、日、时、分、秒、纳秒创建 Carbon 实例
func create(year, month, day, hour, minute, second, nanosecond int, timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
c.time = time.Date(year, time.Month(month), day, hour, minute, second, nanosecond, c.loc)
return c
}

394
vendor/github.com/dromara/carbon/v2/database.go generated vendored Normal file
View File

@@ -0,0 +1,394 @@
package carbon
import (
"bytes"
"database/sql/driver"
"fmt"
"strconv"
"time"
)
// timestamp precision constants
// 时间戳精度常量
const (
PrecisionSecond = 9
PrecisionMillisecond = 999
PrecisionMicrosecond = 999999
PrecisionNanosecond = 999999999
)
// returns a failed scan error
// 失败的扫描错误
var failedScanError = func(src interface{}) error {
return fmt.Errorf("failed to scan value: %v", src)
}
// LayoutFactory defines a LayoutFactory interface
// 定义 LayoutFactory 接口
type LayoutFactory interface {
~string
SetLayout() string
}
// LayoutType defines a LayoutType generic struct
// 定义 LayoutType 泛型结构体
type LayoutType[T LayoutFactory] struct {
*Carbon
}
// FormatFactory defines a FormatFactory interface.
// 定义 FormatFactory 接口
type FormatFactory interface {
~string
SetFormat() string
}
// FormatType defines a FormatType generic struct.
// 定义 FormatType 泛型结构体
type FormatType[T FormatFactory] struct {
*Carbon
}
// TimestampFactory defines a TimestampFactory interface.
// 定义 TimestampFactory 接口
type TimestampFactory interface {
~int64
SetPrecision() int64
}
// TimestampType defines a TimestampType generic struct.
// 定义 TimestampType 泛型结构体
type TimestampType[T TimestampFactory] struct {
*Carbon
}
// NewLayoutType returns a new LayoutType generic instance.
// 返回 LayoutType 泛型实例
func NewLayoutType[T LayoutFactory](carbon *Carbon) LayoutType[T] {
return LayoutType[T]{
Carbon: carbon,
}
}
// NewFormatType returns a new FormatType generic instance.
// 返回 FormatType 泛型实例
func NewFormatType[T FormatFactory](carbon *Carbon) FormatType[T] {
return FormatType[T]{
Carbon: carbon,
}
}
// NewTimestampType returns a new TimestampType generic instance.
// 返回 TimestampType 泛型实例
func NewTimestampType[T TimestampFactory](carbon *Carbon) TimestampType[T] {
return TimestampType[T]{
Carbon: carbon,
}
}
// Scan implements driver.Scanner interface for LayoutType generic struct.
// 实现 driver.Scanner 接口
func (t *LayoutType[T]) Scan(src interface{}) error {
c := NewCarbon()
switch v := src.(type) {
case []byte:
c = Parse(string(v), DefaultTimezone)
case string:
c = Parse(v, DefaultTimezone)
case time.Time:
c = CreateFromStdTime(v, DefaultTimezone)
case int64:
c = CreateFromTimestamp(v, DefaultTimezone)
default:
return failedScanError(v)
}
*t = NewLayoutType[T](c)
return t.Error
}
// Value implements driver.Valuer interface for LayoutType generic struct.
// 实现 driver.Valuer 接口
func (t LayoutType[T]) Value() (driver.Value, error) {
if t.IsNil() || t.IsZero() {
return nil, nil
}
if t.HasError() {
return nil, t.Error
}
return t.StdTime(), nil
}
// MarshalJSON implements json.Marshal interface for LayoutType generic struct.
// 实现 json.Marshaler 接口
func (t LayoutType[T]) MarshalJSON() ([]byte, error) {
emptyBytes := []byte(`""`)
if t.IsNil() || t.IsZero() {
return emptyBytes, nil
}
if t.HasError() {
return emptyBytes, t.Error
}
return []byte(fmt.Sprintf(`"%s"`, t.Layout(t.getLayout(), t.Timezone()))), nil
}
// UnmarshalJSON implements json.Unmarshal interface for LayoutType generic struct.
// 实现 json.Unmarshaler 接口
func (t *LayoutType[T]) UnmarshalJSON(b []byte) error {
value := string(bytes.Trim(b, `"`))
if value == "" || value == "null" || value == "0" {
t.Carbon = nil
return nil
}
*t = NewLayoutType[T](ParseByLayout(value, t.getLayout()))
return t.Error
}
// String implements Stringer interface for LayoutType generic struct.
// 实现 Stringer 接口
func (t LayoutType[T]) String() string {
if t.IsZero() || t.IsInvalid() {
return ""
}
return t.Layout(t.getLayout(), t.Timezone())
}
// GormDataType sets gorm data type for LayoutType generic struct.
// 设置 gorm 数据类型
func (t LayoutType[T]) GormDataType() string {
return "time"
}
// getLayout returns the set layout.
// 返回设置的布局模板
func (t LayoutType[T]) getLayout() string {
var factory T
return factory.SetLayout()
}
// Scan implements driver.Scanner interface for FormatType generic struct.
// 实现 driver.Scanner 接口
func (t *FormatType[T]) Scan(src interface{}) error {
c := NewCarbon()
switch v := src.(type) {
case []byte:
c = Parse(string(v), DefaultTimezone)
case string:
c = Parse(v, DefaultTimezone)
case time.Time:
c = CreateFromStdTime(v, DefaultTimezone)
case int64:
c = CreateFromTimestamp(v, DefaultTimezone)
default:
return failedScanError(v)
}
*t = NewFormatType[T](c)
return t.Error
}
// Value implements driver.Valuer interface for FormatType generic struct.
// 实现 driver.Valuer 接口
func (t FormatType[T]) Value() (driver.Value, error) {
if t.IsNil() || t.IsZero() {
return nil, nil
}
if t.HasError() {
return nil, t.Error
}
return t.StdTime(), nil
}
// MarshalJSON implements json.Marshal interface for FormatType generic struct.
// 实现 json.Marshaler 接口
func (t FormatType[T]) MarshalJSON() ([]byte, error) {
emptyBytes := []byte(`""`)
if t.IsNil() || t.IsZero() {
return emptyBytes, nil
}
if t.HasError() {
return emptyBytes, t.Error
}
return []byte(fmt.Sprintf(`"%s"`, t.Format(t.getFormat(), t.Timezone()))), nil
}
// UnmarshalJSON implements json.Unmarshal interface for FormatType generic struct.
// 实现 json.Unmarshaler 接口
func (t *FormatType[T]) UnmarshalJSON(b []byte) error {
value := string(bytes.Trim(b, `"`))
if value == "" || value == "null" || value == "0" {
t.Carbon = nil
return nil
}
*t = NewFormatType[T](ParseByFormat(value, t.getFormat()))
return t.Error
}
// String implements Stringer interface for FormatType generic struct.
// 实现 Stringer 接口
func (t FormatType[T]) String() string {
if t.IsZero() || t.IsInvalid() {
return ""
}
return t.Format(t.getFormat(), t.Timezone())
}
// GormDataType sets gorm data type for FormatType generic struct.
// 设置 gorm 数据类型
func (t FormatType[T]) GormDataType() string {
return "time"
}
// getFormat returns the set format.
// 返回设置的格式模板
func (t FormatType[T]) getFormat() string {
var factory T
return factory.SetFormat()
}
// Scan implements driver.Scanner interface for TimestampType generic struct.
// 实现 driver.Scanner 接口
func (t *TimestampType[T]) Scan(src interface{}) (err error) {
ts := int64(0)
c := NewCarbon()
switch v := src.(type) {
case []byte:
ts, err = strconv.ParseInt(string(v), 10, 64)
if err != nil {
return invalidTimestampError(string(v))
}
case string:
ts, err = strconv.ParseInt(v, 10, 64)
if err != nil {
return invalidTimestampError(v)
}
case int64:
ts = v
case time.Time:
c = CreateFromStdTime(v, DefaultTimezone)
*t = NewTimestampType[T](c)
return t.Error
default:
return failedScanError(src)
}
switch t.getPrecision() {
case PrecisionSecond:
c = CreateFromTimestamp(ts, DefaultTimezone)
case PrecisionMillisecond:
c = CreateFromTimestampMilli(ts, DefaultTimezone)
case PrecisionMicrosecond:
c = CreateFromTimestampMicro(ts, DefaultTimezone)
case PrecisionNanosecond:
c = CreateFromTimestampNano(ts, DefaultTimezone)
}
*t = NewTimestampType[T](c)
return t.Error
}
// Value implements driver.Valuer interface for TimestampType generic struct.
// 实现 driver.Valuer 接口
func (t TimestampType[T]) Value() (driver.Value, error) {
if t.IsNil() || t.IsZero() {
return nil, nil
}
if t.HasError() {
return nil, t.Error
}
v := int64(0)
switch t.getPrecision() {
case PrecisionSecond:
v = t.Timestamp()
case PrecisionMillisecond:
v = t.TimestampMilli()
case PrecisionMicrosecond:
v = t.TimestampMicro()
case PrecisionNanosecond:
v = t.TimestampNano()
}
return v, nil
}
// MarshalJSON implements json.Marshal interface for TimestampType generic struct.
// 实现 json.Marshaler 接口
func (t TimestampType[T]) MarshalJSON() ([]byte, error) {
ts := int64(0)
if t.IsNil() || t.IsZero() {
return []byte(fmt.Sprintf(`%d`, ts)), nil
}
if t.HasError() {
return []byte(fmt.Sprintf(`%d`, ts)), t.Error
}
switch t.getPrecision() {
case PrecisionSecond:
ts = t.Timestamp()
case PrecisionMillisecond:
ts = t.TimestampMilli()
case PrecisionMicrosecond:
ts = t.TimestampMicro()
case PrecisionNanosecond:
ts = t.TimestampNano()
}
return []byte(fmt.Sprintf(`%d`, ts)), nil
}
// UnmarshalJSON implements json.Unmarshal interface for TimestampType generic struct.
// 实现 json.Unmarshaler 接口
func (t *TimestampType[T]) UnmarshalJSON(b []byte) error {
value := string(bytes.Trim(b, `"`))
c := NewCarbon()
if value == "" || value == "null" || value == "0" {
t.Carbon = nil
return nil
}
ts, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return invalidTimestampError(value)
}
switch t.getPrecision() {
case PrecisionSecond:
c = CreateFromTimestamp(ts, DefaultTimezone)
case PrecisionMillisecond:
c = CreateFromTimestampMilli(ts, DefaultTimezone)
case PrecisionMicrosecond:
c = CreateFromTimestampMicro(ts, DefaultTimezone)
case PrecisionNanosecond:
c = CreateFromTimestampNano(ts, DefaultTimezone)
}
*t = NewTimestampType[T](c)
return t.Error
}
// String implements Stringer interface for TimestampType generic struct.
// 实现 Stringer 接口
func (t TimestampType[T]) String() string {
return strconv.FormatInt(t.Int64(), 10)
}
func (t TimestampType[T]) Int64() int64 {
ts := int64(0)
if t.IsZero() || t.IsInvalid() {
return ts
}
switch t.getPrecision() {
case PrecisionSecond:
ts = t.Timestamp()
case PrecisionMillisecond:
ts = t.TimestampMilli()
case PrecisionMicrosecond:
ts = t.TimestampMicro()
case PrecisionNanosecond:
ts = t.TimestampNano()
}
return ts
}
// GormDataType sets gorm data type for TimestampType generic struct.
// 设置 gorm 数据类型
func (t TimestampType[T]) GormDataType() string {
return "time"
}
// getPrecision returns the set timestamp precision.
// 返回设置的时间戳精度
func (t TimestampType[T]) getPrecision() int64 {
var factory T
return factory.SetPrecision()
}

60
vendor/github.com/dromara/carbon/v2/default.go generated vendored Normal file
View File

@@ -0,0 +1,60 @@
package carbon
import "time"
var (
// DefaultLayout default layout
// 默认布局模板
DefaultLayout = DateTimeLayout
// DefaultTimezone default timezone
// 默认时区
DefaultTimezone = UTC
// DefaultWeekStartsAt default default week start date
// 默认一周开始日期
DefaultWeekStartsAt = Sunday
// DefaultLocale default language locale
// 默认语言区域
DefaultLocale = "en"
)
// Default defines a Default struct.
// 定义 Default 结构体
type Default struct {
Layout string
Timezone string
WeekStartsAt string
Locale string
}
// SetDefault sets default.
// 设置全局默认值
func SetDefault(d Default) {
if d.Layout != "" {
DefaultLayout = d.Layout
}
if d.Timezone != "" {
loc, err := getLocationByTimezone(d.Timezone)
if err == nil {
time.Local = loc
DefaultTimezone = d.Timezone
}
}
if d.WeekStartsAt != "" {
DefaultWeekStartsAt = d.WeekStartsAt
}
if d.Locale != "" {
DefaultLocale = d.Locale
}
}
// ResetDefault resets default.
// 重置全局默认值
func ResetDefault() {
DefaultLayout = DateTimeLayout
DefaultTimezone = UTC
DefaultWeekStartsAt = Sunday
DefaultLocale = "en"
}

289
vendor/github.com/dromara/carbon/v2/difference.go generated vendored Normal file
View File

@@ -0,0 +1,289 @@
package carbon
import (
"math"
"strings"
"time"
)
const (
minDuration time.Duration = -1 << 63
maxDuration time.Duration = 1<<63 - 1
)
// DiffInYears gets the difference in years.
// 相差多少年
func (c *Carbon) DiffInYears(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
dy, dm, dd := end.Year()-start.Year(), end.Month()-start.Month(), end.Day()-start.Day()
if dm < 0 || (dm == 0 && dd < 0) {
dy--
}
if dy < 0 && (dd != 0 || dm != 0) {
dy++
}
return int64(dy)
}
// DiffAbsInYears gets the difference in years with absolute value.
// 相差多少年(绝对值)
func (c *Carbon) DiffAbsInYears(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInYears(carbon...))
}
// DiffInMonths gets the difference in months.
// 相差多少月
func (c *Carbon) DiffInMonths(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
if start.Month() == end.Month() && start.Year() == end.Year() {
return 0
}
dd := start.DiffInDays(end)
sign := 1
if dd <= 0 {
start, end = end, start
sign = -1
}
months := getDiffInMonths(start, end)
return months * int64(sign)
}
// DiffAbsInMonths gets the difference in months with absolute value.
// 相差多少月(绝对值)
func (c *Carbon) DiffAbsInMonths(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInMonths(carbon...))
}
// DiffInWeeks gets the difference in weeks.
// 相差多少周
func (c *Carbon) DiffInWeeks(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (7 * 24 * 3600))))
}
// DiffAbsInWeeks gets the difference in weeks with absolute value.
// 相差多少周(绝对值)
func (c *Carbon) DiffAbsInWeeks(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInWeeks(carbon...))
}
// DiffInDays gets the difference in days.
// 相差多少天
func (c *Carbon) DiffInDays(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (24 * 3600))))
}
// DiffAbsInDays gets the difference in days with absolute value.
// 相差多少天(绝对值)
func (c *Carbon) DiffAbsInDays(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInDays(carbon...))
}
// DiffInHours gets the difference in hours.
// 相差多少小时
func (c *Carbon) DiffInHours(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
return start.DiffInSeconds(end) / SecondsPerHour
}
// DiffAbsInHours gets the difference in hours with absolute value.
// 相差多少小时(绝对值)
func (c *Carbon) DiffAbsInHours(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInHours(carbon...))
}
// DiffInMinutes gets the difference in minutes.
// 相差多少分钟
func (c *Carbon) DiffInMinutes(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
return start.DiffInSeconds(end) / SecondsPerMinute
}
// DiffAbsInMinutes gets the difference in minutes with absolute value.
// 相差多少分钟(绝对值)
func (c *Carbon) DiffAbsInMinutes(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInMinutes(carbon...))
}
// DiffInSeconds gets the difference in seconds.
// 相差多少秒
func (c *Carbon) DiffInSeconds(carbon ...*Carbon) int64 {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
return end.Timestamp() - start.Timestamp()
}
// DiffAbsInSeconds gets the difference in seconds with absolute value.
// 相差多少秒(绝对值)
func (c *Carbon) DiffAbsInSeconds(carbon ...*Carbon) int64 {
return getAbsValue(c.DiffInSeconds(carbon...))
}
// DiffInString gets the difference in string, i18n is supported.
// 相差字符串,支持 i18n
func (c *Carbon) DiffInString(carbon ...*Carbon) string {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return ""
}
unit, value := start.diff(end)
return c.lang.translate(unit, value)
}
// DiffAbsInString gets the difference in string with absolute value, i18n is supported.
// 相差字符串,支持 i18n(绝对值)
func (c *Carbon) DiffAbsInString(carbon ...*Carbon) string {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return ""
}
unit, value := start.diff(end)
return c.lang.translate(unit, getAbsValue(value))
}
// DiffInDuration gets the difference in duration.
// 相差时长
func (c *Carbon) DiffInDuration(carbon ...*Carbon) time.Duration {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return 0
}
return end.StdTime().Sub(start.StdTime())
}
// DiffAbsInDuration gets the difference in duration with absolute value.
// 相差时长(绝对值)
func (c *Carbon) DiffAbsInDuration(carbon ...*Carbon) time.Duration {
d := c.DiffInDuration(carbon...)
if d >= 0 {
return d
}
return -d
}
// DiffForHumans gets the difference in a human-readable format, i18n is supported.
// 获取对人类友好的可读格式时间差,支持 i18n
func (c *Carbon) DiffForHumans(carbon ...*Carbon) string {
start, end := c, Now(c.Timezone())
if len(carbon) > 0 {
end = carbon[0]
}
if start.IsInvalid() || end.IsInvalid() {
return ""
}
unit, value := start.diff(end)
translation := c.lang.translate(unit, getAbsValue(value))
if unit == "now" {
return translation
}
if c.Lt(end) && len(carbon) == 0 {
return strings.Replace(c.lang.resources["ago"], "%s", translation, 1)
}
if c.Lt(end) && len(carbon) > 0 {
return strings.Replace(c.lang.resources["before"], "%s", translation, 1)
}
if c.Gt(end) && len(carbon) == 0 {
return strings.Replace(c.lang.resources["from_now"], "%s", translation, 1)
}
return strings.Replace(c.lang.resources["after"], "%s", translation, 1)
}
// gets the difference for unit and value.
// 获取相差单位和差值
func (c *Carbon) diff(end *Carbon) (unit string, value int64) {
switch true {
case c.DiffAbsInYears(end) > 0:
unit = "year"
value = c.DiffInYears(end)
case c.DiffAbsInMonths(end) > 0:
unit = "month"
value = c.DiffInMonths(end)
case c.DiffAbsInWeeks(end) > 0:
unit = "week"
value = c.DiffInWeeks(end)
case c.DiffAbsInDays(end) > 0:
unit = "day"
value = c.DiffInDays(end)
case c.DiffAbsInHours(end) > 0:
unit = "hour"
value = c.DiffInHours(end)
case c.DiffAbsInMinutes(end) > 0:
unit = "minute"
value = c.DiffInMinutes(end)
case c.DiffAbsInSeconds(end) > 0:
unit = "second"
value = c.DiffInSeconds(end)
case c.DiffAbsInSeconds(end) == 0:
unit = "now"
value = 0
}
return
}
func getDiffInMonths(start, end *Carbon) int64 {
if start.IsInvalid() || end.IsInvalid() {
return 0
}
y, m, d, h, i, s, ns := start.DateTimeNano()
endYear, endMonth, _ := end.Date()
yearDiff := endYear - y
monthDiff := endMonth - m
totalMonths := yearDiff*12 + monthDiff
if time.Date(y, time.Month(m+totalMonths), d, h, i, s, ns, start.StdTime().Location()).After(end.StdTime()) {
return int64(totalMonths - 1)
}
return int64(totalMonths)
}

89
vendor/github.com/dromara/carbon/v2/errors.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
package carbon
import (
"fmt"
)
// returns a failed parse error.
// 解析失败错误
var failedParseError = func(value string) error {
return fmt.Errorf("cannot parse %q as carbon, please make sure the value is valid", value)
}
// returns a invalid timestamp error.
// 无效的时间戳错误
var invalidTimestampError = func(value string) error {
return fmt.Errorf("invalid timestamp %s, please make sure the timestamp is valid", value)
}
// returns a nil location error.
// 无效的位置错误
var nilLocationError = func() error {
return fmt.Errorf("location cannot be nil")
}
// returns a nil language error.
// 无效的语言错误
var nilLanguageError = func() error {
return fmt.Errorf("language cannot be nil")
}
// returns a empty timezone error.
// 空的时区错误
var emptyTimezoneError = func() error {
return fmt.Errorf("timezone cannot be empty")
}
// returns an invalid timezone error.
// 无效的时区错误
var invalidTimezoneError = func(timezone string) error {
return fmt.Errorf("invalid timezone %q, please see the file %q for all valid timezones", timezone, "$GOROOT/lib/time/zoneinfo.zip")
}
// returns an empty duration error.
// 空的时长错误
var emptyDurationError = func() error {
return fmt.Errorf("duration cannot be empty")
}
// returns an invalid duration error.
// 无效的时长错误
var invalidDurationError = func(duration string) error {
return fmt.Errorf("invalid duration %q, please make sure the duration is valid", duration)
}
// returns an empty layout error.
// 空的布局模板错误
var emptyLayoutError = func() error {
return fmt.Errorf("layout cannot be empty")
}
// returns an invalid layout error.
// 无效的布局模板错误
var invalidLayoutError = func(value, layout string) error {
return fmt.Errorf("cannot parse string %q as carbon by layout %q, please make sure the value and layout match", value, layout)
}
// returns an empty format error.
// 空的格式模板错误
var emptyFormatError = func() error {
return fmt.Errorf("format cannot be empty")
}
// returns an invalid format error.
// 无效的格式模板错误
var invalidFormatError = func(value, format string) error {
return fmt.Errorf("cannot parse string %q as carbon by format %q, please make sure the value and format match", value, format)
}
// returns an empty week starts day error.
// 空的周起始日期错误
var emptyWeekStartsDayError = func() error {
return fmt.Errorf("week start day cannot be empty")
}
// returns an invalid week starts at day error.
// 无效的周起始日期错误
var invalidWeekStartsAtError = func(day string) error {
return fmt.Errorf("invalid week starts at day %s, please make sure the day is valid", day)
}

67
vendor/github.com/dromara/carbon/v2/extremum.go generated vendored Normal file
View File

@@ -0,0 +1,67 @@
package carbon
// MaxValue returns a Carbon instance for the greatest supported date.
// 返回 Carbon 的最大值
func MaxValue() *Carbon {
return create(9999, 12, 31, 23, 59, 59, 999999999, UTC)
}
// MinValue returns a Carbon instance for the lowest supported date.
// 返回 Carbon 的最小值
func MinValue() *Carbon {
return create(-9998, 1, 1, 0, 0, 0, 0, UTC)
}
// Max returns the maximum Carbon instance from the given Carbon instance (second-precision).
// 返回最大的 Carbon 实例
func Max(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
c = c1
for i := range c2 {
if c.IsInvalid() || c2[i].IsInvalid() {
return nil
}
if c2[i].Gte(c) {
c = c2[i]
}
}
return
}
// Min returns the minimum Carbon instance from the given Carbon instance (second-precision).
// 返回最小的 Carbon 实例
func Min(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
c = c1
for i := range c2 {
if c.IsInvalid() || c2[i].IsInvalid() {
return nil
}
if c2[i].Lte(c) {
c = c2[i]
}
}
return
}
// Closest returns the closest Carbon instance from the given Carbon instance.
// 返回离给定 carbon 实例最近的 Carbon 实例
func (c *Carbon) Closest(c1 *Carbon, c2 *Carbon) *Carbon {
if c.IsInvalid() || c1.IsInvalid() || c2.IsInvalid() {
return nil
}
if c.DiffAbsInSeconds(c1) < c.DiffAbsInSeconds(c2) {
return c1
}
return c2
}
// Farthest returns the farthest Carbon instance from the given Carbon instance.
// 返回离给定 carbon 实例最远的 Carbon 实例
func (c *Carbon) Farthest(c1 *Carbon, c2 *Carbon) *Carbon {
if c.IsInvalid() || c1.IsInvalid() || c2.IsInvalid() {
return nil
}
if c.DiffAbsInSeconds(c1) > c.DiffAbsInSeconds(c2) {
return c1
}
return c2
}

41
vendor/github.com/dromara/carbon/v2/frozen.go generated vendored Normal file
View File

@@ -0,0 +1,41 @@
package carbon
import "sync"
type TestNow struct {
isFrozen bool
frozenNow *Carbon
rw *sync.RWMutex
}
var testNow = &TestNow{
rw: new(sync.RWMutex),
}
// SetTestNow sets a test Carbon instance (real or mock) to be returned when a "now" instance is created.
// 设置当前测试时间
func SetTestNow(carbon *Carbon) {
testNow.rw.Lock()
defer testNow.rw.Unlock()
testNow.isFrozen = true
testNow.frozenNow = carbon
}
// CleanTestNow clears a test Carbon instance (real or mock) to be returned when a "now" instance is created.
// 清除当前测试时间
func CleanTestNow() {
testNow.rw.Lock()
defer testNow.rw.Unlock()
testNow.isFrozen = false
}
// IsTestNow report whether is testing time.
// 是否是测试时间
func IsTestNow() bool {
testNow.rw.Lock()
defer testNow.rw.Unlock()
return testNow.isFrozen
}

458
vendor/github.com/dromara/carbon/v2/getter.go generated vendored Normal file
View File

@@ -0,0 +1,458 @@
package carbon
import (
"time"
)
// StdTime gets standard time.Time.
// 获取标准 time.Time
func (c *Carbon) StdTime() time.Time {
if c.loc == nil {
return c.time
}
return c.time.In(c.loc)
}
// DaysInYear gets total days in year like 365.
// 获取本年的总天数
func (c *Carbon) DaysInYear() int {
if c.IsInvalid() {
return 0
}
if c.IsLeapYear() {
return DaysPerLeapYear
}
return DaysPerNormalYear
}
// DaysInMonth gets total days in month like 30.
// 获取本月的总天数
func (c *Carbon) DaysInMonth() int {
if c.IsInvalid() {
return 0
}
return c.EndOfMonth().StdTime().Day()
}
// MonthOfYear gets month of year like 12.
// 获取本年的第几月
func (c *Carbon) MonthOfYear() int {
if c.IsInvalid() {
return 0
}
return int(c.StdTime().Month())
}
// DayOfYear gets day of year like 365.
// 获取本年的第几天
func (c *Carbon) DayOfYear() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().YearDay()
}
// DayOfMonth gets day of month like 30.
// 获取本月的第几天
func (c *Carbon) DayOfMonth() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Day()
}
// DayOfWeek gets day of week like 6.
// 获取本周的第几天
func (c *Carbon) DayOfWeek() int {
if c.IsInvalid() {
return 0
}
day := int(c.StdTime().Weekday())
if day == 0 {
return DaysPerWeek
}
return day
}
// WeekOfYear gets week of year like 1, see https://en.wikipedia.org/wiki/ISO_8601#Week_dates.
// 获取本年的第几周
func (c *Carbon) WeekOfYear() int {
if c.IsInvalid() {
return 0
}
_, week := c.StdTime().ISOWeek()
return week
}
// WeekOfMonth gets week of month like 1.
// 获取本月的第几周
func (c *Carbon) WeekOfMonth() int {
if c.IsInvalid() {
return 0
}
days := c.Day() + c.StartOfMonth().DayOfWeek() - 1
if days%DaysPerWeek == 0 {
return days / DaysPerWeek
}
return days/DaysPerWeek + 1
}
// DateTime gets current year, month, day, hour, minute, and second like 2020, 8, 5, 13, 14, 15.
// 获取当前年、月、日、时、分、秒
func (c *Carbon) DateTime() (year, month, day, hour, minute, second int) {
if c.IsInvalid() {
return
}
year, month, day = c.Date()
hour, minute, second = c.Time()
return year, month, day, hour, minute, second
}
// DateTimeMilli gets current year, month, day, hour, minute, second and millisecond like 2020, 8, 5, 13, 14, 15, 999.
// 获取当前年、月、日、时、分、秒、毫秒
func (c *Carbon) DateTimeMilli() (year, month, day, hour, minute, second, millisecond int) {
if c.IsInvalid() {
return
}
year, month, day, hour, minute, second = c.DateTime()
return year, month, day, hour, minute, second, c.Millisecond()
}
// DateTimeMicro gets current year, month, day, hour, minute, second and microsecond like 2020, 8, 5, 13, 14, 15, 999999.
// 获取当前年、月、日、时、分、秒、微秒
func (c *Carbon) DateTimeMicro() (year, month, day, hour, minute, second, microsecond int) {
if c.IsInvalid() {
return
}
year, month, day, hour, minute, second = c.DateTime()
return year, month, day, hour, minute, second, c.Microsecond()
}
// DateTimeNano gets current year, month, day, hour, minute, second and nanosecond like 2020, 8, 5, 13, 14, 15, 999999999.
// 获取当前年、月、日、时、分、秒、纳秒
func (c *Carbon) DateTimeNano() (year, month, day, hour, minute, second, nanosecond int) {
if c.IsInvalid() {
return
}
year, month, day, hour, minute, second = c.DateTime()
return year, month, day, hour, minute, second, c.Nanosecond()
}
// Date gets current year, month, and day like 2020, 8, 5.
// 获取当前年、月、日
func (c *Carbon) Date() (year, month, day int) {
if c.IsInvalid() {
return
}
var tm time.Month
year, tm, day = c.StdTime().Date()
return year, int(tm), day
}
// DateMilli gets current year, month, day and millisecond like 2020, 8, 5, 999.
// 获取当前年、月、日、毫秒
func (c *Carbon) DateMilli() (year, month, day, millisecond int) {
if c.IsInvalid() {
return
}
year, month, day = c.Date()
return year, month, day, c.Millisecond()
}
// DateMicro gets current year, month, day and microsecond like 2020, 8, 5, 999999.
// 获取当前年、月、日、微秒
func (c *Carbon) DateMicro() (year, month, day, microsecond int) {
if c.IsInvalid() {
return
}
year, month, day = c.Date()
return year, month, day, c.Microsecond()
}
// DateNano gets current year, month, day and nanosecond like 2020, 8, 5, 999999999.
// 获取当前年、月、日、纳秒
func (c *Carbon) DateNano() (year, month, day, nanosecond int) {
if c.IsInvalid() {
return
}
year, month, day = c.Date()
return year, month, day, c.Nanosecond()
}
// Time gets current hour, minute, and second like 13, 14, 15.
// 获取当前时、分、秒
func (c *Carbon) Time() (hour, minute, second int) {
if c.IsInvalid() {
return
}
return c.StdTime().Clock()
}
// TimeMilli gets current hour, minute, second and millisecond like 13, 14, 15, 999.
// 获取当前时、分、秒、毫秒
func (c *Carbon) TimeMilli() (hour, minute, second, millisecond int) {
if c.IsInvalid() {
return
}
hour, minute, second = c.Time()
return hour, minute, second, c.Millisecond()
}
// TimeMicro gets current hour, minute, second and microsecond like 13, 14, 15, 999999.
// 获取当前时、分、秒、微秒
func (c *Carbon) TimeMicro() (hour, minute, second, microsecond int) {
if c.IsInvalid() {
return
}
hour, minute, second = c.Time()
return hour, minute, second, c.Microsecond()
}
// TimeNano gets current hour, minute, second and nanosecond like 13, 14, 15, 999999999.
// 获取当前时、分、秒、纳秒
func (c *Carbon) TimeNano() (hour, minute, second, nanosecond int) {
if c.IsInvalid() {
return
}
hour, minute, second = c.Time()
return hour, minute, second, c.Nanosecond()
}
// Century gets current century like 21.
// 获取当前世纪
func (c *Carbon) Century() int {
if c.IsInvalid() {
return 0
}
return c.Year()/YearsPerCentury + 1
}
// Decade gets current decade like 20.
// 获取当前年代
func (c *Carbon) Decade() int {
if c.IsInvalid() {
return 0
}
return c.Year() % YearsPerCentury / YearsPerDecade * YearsPerDecade
}
// Year gets current year like 2020.
// 获取当前年
func (c *Carbon) Year() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Year()
}
// Quarter gets current quarter like 3.
// 获取当前季度
func (c *Carbon) Quarter() (quarter int) {
if c.IsInvalid() {
return
}
month := c.Month()
switch {
case month >= 10:
quarter = 4
case month >= 7:
quarter = 3
case month >= 4:
quarter = 2
case month >= 1:
quarter = 1
}
return
}
// Month gets current month like 8.
// 获取当前月
func (c *Carbon) Month() int {
return c.MonthOfYear()
}
// Week gets current week like 6, start from 0.
// 获取当前周(从0开始)
func (c *Carbon) Week() int {
if c.IsInvalid() {
return -1
}
return (c.DayOfWeek() + DaysPerWeek - int(c.weekStartsAt)) % DaysPerWeek
}
// Day gets current day like 5.
// 获取当前日
func (c *Carbon) Day() int {
return c.DayOfMonth()
}
// Hour gets current hour like 13.
// 获取当前小时
func (c *Carbon) Hour() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Hour()
}
// Minute gets current minute like 14.
// 获取当前分钟数
func (c *Carbon) Minute() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Minute()
}
// Second gets current second like 9.
// 获取当前秒数
func (c *Carbon) Second() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Second()
}
// Millisecond gets current millisecond like 999.
// 获取当前毫秒数
func (c *Carbon) Millisecond() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Nanosecond() / 1e6
}
// Microsecond gets current microsecond like 999999.
// 获取当前微秒数
func (c *Carbon) Microsecond() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Nanosecond() / 1e3
}
// Nanosecond gets current nanosecond like 999999999.
// 获取当前纳秒数
func (c *Carbon) Nanosecond() int {
if c.IsInvalid() {
return 0
}
return c.StdTime().Nanosecond()
}
// Timestamp gets timestamp with second like 1596604455.
// 输出秒级时间戳
func (c *Carbon) Timestamp() int64 {
if c.IsInvalid() {
return 0
}
return c.StdTime().Unix()
}
// TimestampMilli gets timestamp with millisecond like 1596604455000.
// 获取毫秒级时间戳
func (c *Carbon) TimestampMilli() int64 {
if c.IsInvalid() {
return 0
}
t := c.StdTime()
return t.Unix()*1e3 + int64(t.Nanosecond())/1e6
}
// TimestampMicro gets timestamp with microsecond like 1596604455000000.
// 获取微秒级时间戳
func (c *Carbon) TimestampMicro() int64 {
if c.IsInvalid() {
return 0
}
t := c.StdTime()
return t.Unix()*1e6 + int64(t.Nanosecond())/1e3
}
// TimestampNano gets timestamp with nanosecond like 1596604455000000000.
// 获取纳秒级时间戳
func (c *Carbon) TimestampNano() int64 {
if c.IsInvalid() {
return 0
}
return c.StdTime().UnixNano()
}
// Timezone gets timezone location like "Asia/Shanghai".
// 获取时区位置
func (c *Carbon) Timezone() string {
if c.IsInvalid() {
return ""
}
return c.loc.String()
}
// ZoneName gets timezone name like "CST".
// 获取时区名称
func (c *Carbon) ZoneName() string {
if c.IsInvalid() {
return ""
}
if c.IsZero() {
// prevent returning to LMT timezone before 1901
name, _ := time.Now().In(c.loc).Zone()
return name
}
name, _ := c.StdTime().Zone()
return name
}
// ZoneOffset gets timezone offset seconds from the UTC timezone like 28800.
// 获取时区偏移量,单位秒
func (c *Carbon) ZoneOffset() int {
if c.IsInvalid() {
return 0
}
if c.IsZero() {
// prevent returning to LMT timezone before 1901
_, offset := time.Now().In(c.loc).Zone()
return offset
}
_, offset := c.StdTime().Zone()
return offset
}
// Locale gets locale name like "zh-CN".
// 获取语言区域
func (c *Carbon) Locale() string {
if c.IsInvalid() {
return ""
}
return c.lang.locale
}
// WeekStartsAt returns start day of the week.
// 获取一周的开始日期
func (c *Carbon) WeekStartsAt() string {
if c.IsInvalid() {
return ""
}
return c.weekStartsAt.String()
}
// CurrentLayout returns the layout used for parsing the time string.
// 获取当前布局模板
func (c *Carbon) CurrentLayout() string {
if c.IsInvalid() {
return ""
}
return c.layout
}
// Age gets age like 18.
// 获取年龄
func (c *Carbon) Age() int {
if c.IsInvalid() {
return 0
}
now := Now(c.Timezone())
if c.Gte(now) {
return 0
}
return int(c.DiffInYears(now))
}

138
vendor/github.com/dromara/carbon/v2/helper.go generated vendored Normal file
View File

@@ -0,0 +1,138 @@
package carbon
import (
"bytes"
"time"
)
// week days
// 工作日
var weekdays = map[string]time.Weekday{
Monday: time.Monday,
Tuesday: time.Tuesday,
Wednesday: time.Wednesday,
Thursday: time.Thursday,
Friday: time.Friday,
Saturday: time.Saturday,
Sunday: time.Sunday,
}
// format map
// 格式化符号映射表
var formatMap = map[byte]string{
'd': "02", // Day: Day of the month, 2 digits with leading zeros. Eg: 01 to 31.
'D': "Mon", // Day: A textual representation of a day, three letters. Eg: Mon through Sun.
'j': "2", // Day: Day of the month without leading zeros. Eg: 1 to 31.
'l': "Monday", // Day: A full textual representation of the day of the week. Eg: Sunday through Saturday.
'F': "January", // Month: A full textual representation of a month, such as January or March. Eg: January through December.
'm': "01", // Month: Numeric representation of a month, with leading zeros. Eg: 01 through 12.
'M': "Jan", // Month: A short textual representation of a month, three letters. Eg: Jan through Dec.
'n': "1", // Month: Numeric representation of a month, without leading zeros. Eg: 1 through 12.
'Y': "2006", // Year: A full numeric representation of a year, 4 digits. Eg: 1999 or 2003.
'y': "06", // Year: A two digit representation of a year. Eg: 99 or 03.
'a': "pm", // Time: Lowercase morning or afternoon sign. Eg: am or pm.
'A': "PM", // Time: Uppercase morning or afternoon sign. Eg: AM or PM.
'g': "3", // Time: 12-hour format of an hour without leading zeros. Eg: 1 through 12.
'h': "03", // Time: 12-hour format of an hour with leading zeros. Eg: 01 through 12.
'H': "15", // Time: 24-hour format of an hour with leading zeros. Eg: 00 through 23.
'i': "04", // Time: Minutes with leading zeros. Eg: 00 to 59.
's': "05", // Time: Seconds with leading zeros. Eg: 00 through 59.
'O': "-0700", // Zone: Difference to Greenwich time (GMT) in hours. Eg: +0200.
'P': "-07:00", // Zone: Difference to Greenwich time (GMT) with colon between hours and minutes. Eg: +02:00.
'T': "MST", // Zone: Timezone abbreviation. Eg: UTC, EST, MDT ...
'U': "timestamp", // Timestamp with second. Eg: 1699677240.
'V': "timestampMilli", // TimestampMilli with second. Eg: 1596604455666.
'X': "timestampMicro", // TimestampMicro with second. Eg: 1596604455666666.
'Z': "timestampNano", // TimestampNano with second. Eg: 1596604455666666666.
'v': "999", // Millisecond. Eg: 999.
'x': "999999", // Microsecond. Eg: 999999.
'z': "999999999", // Nanosecond. Eg: 999999999.
}
// supported layouts
// 支持的布局模板
var supportedLayouts = []string{
DateTimeLayout, DateLayout, TimeLayout,
ISO8601Layout, DayDateTimeLayout, ISO8601NanoLayout,
DateTimeNanoLayout, ShortDateTimeLayout, ShortDateTimeNanoLayout,
DateLayout, DateNanoLayout, ShortDateLayout, ShortDateNanoLayout,
TimeMicroLayout, TimeMilliLayout, TimeNanoLayout,
RFC822Layout, RFC822ZLayout, RFC850Layout, RFC1123Layout, RFC1123ZLayout, RFC3339Layout, RFC3339NanoLayout, RFC1036Layout, RFC7231Layout,
KitchenLayout,
CookieLayout,
ANSICLayout,
UnixDateLayout,
RubyDateLayout,
"2006",
"2006-1", "2006-1-2", "2006-1-2 15", "2006-1-2 15:4", "2006-1-2 15:4:5", "2006-1-2 15:4:5.999999999",
"2006.1", "2006.1.2", "2006.1.2 15", "2006.1.2 15:4", "2006.1.2 15:4:5", "2006.1.2 15:4:5.999999999",
"2006/1", "2006/1/2", "2006/1/2 15", "2006/1/2 15:4", "2006/1/2 15:4:5", "2006/1/2 15:4:5.999999999",
"2006-01-02 15:04:05 -0700 MST",
"2006-01-02 15:04:05PM MST", "2006-01-02 15:04:05.999999999PM MST", "2006-1-2 15:4:5PM MST", "2006-1-2 15:4:5.999999999PM MST",
"2006-01-02 15:04:05 PM MST", "2006-01-02 15:04:05.999999999 PM MST", "2006-1-2 15:4:5 PM MST", "2006-1-2 15:4:5.999999999 PM MST",
"1/2/2006", "1/2/2006 15", "1/2/2006 15:4", "1/2/2006 15:4:5", "1/2/2006 15:4:5.999999999",
"2006-1-2 15:4:5 -0700 MST", "2006-1-2 15:4:5.999999999 -0700 MST", "2006-1-2 15:04:05 -0700 MST", "2006-1-2 15:04:05.999999999 -0700 MST",
"2006-01-02T15:04:05", "2006-01-02T15:04:05.999999999", "2006-1-2T3:4:5", "2006-1-2T3:4:5.999999999",
"2006-01-02T15:04:05Z07", "2006-01-02T15:04:05.999999999Z07", "2006-1-2T15:4:5Z07", "2006-1-2T15:4:5.999999999Z07",
"2006-01-02T15:04:05Z07:00", "2006-01-02T15:04:05.999999999Z07:00", "2006-1-2T15:4:5Z07:00", "2006-1-2T15:4:5.999999999Z07:00",
"2006-01-02T15:04:05-07:00", "2006-01-02T15:04:05.999999999-07:00", "2006-1-2T15:4:5-07:00", "2006-1-2T15:4:5.999999999-07:00",
"2006-01-02T15:04:05-0700", "2006-01-02T15:04:05.999999999-0700", "2006-1-2T3:4:5-0700", "2006-1-2T3:4:5.999999999-0700",
"20060102150405-07:00", "20060102150405.999999999-07:00",
"20060102150405Z07", "20060102150405.999999999Z07",
"20060102150405Z07:00", "20060102150405.999999999Z07:00",
}
// converts format to layout.
// format 转 layout
func format2layout(format string) string {
buffer := bytes.NewBuffer(nil)
for i := 0; i < len(format); i++ {
if layout, ok := formatMap[format[i]]; ok {
buffer.WriteString(layout)
} else {
switch format[i] {
case '\\': // raw output, no parse
buffer.WriteByte(format[i+1])
i++
continue
default:
buffer.WriteByte(format[i])
}
}
}
return buffer.String()
}
// gets a Location instance by a timezone string.
// 通过时区获取 Location 实例
func getLocationByTimezone(timezone string) (*time.Location, error) {
if timezone == "" {
return nil, emptyTimezoneError()
}
loc, err := time.LoadLocation(timezone)
if err != nil {
err = invalidTimezoneError(timezone)
}
return loc, err
}
// parses as a Duration instance by a duration string.
// 通过时长解析
func parseByDuration(duration string) (time.Duration, error) {
if duration == "" {
return 0, emptyDurationError()
}
td, err := time.ParseDuration(duration)
if err != nil {
err = invalidDurationError(duration)
}
return td, err
}
// gets absolute value.
// 获取绝对值
func getAbsValue(value int64) int64 {
return (value ^ value>>31) - value>>31
}

22
vendor/github.com/dromara/carbon/v2/lang/ar.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Arabic",
"author": "zumoshi",
"months": "يناير|فبراير|مارس|أبريل|مايو|يونيو|يوليو|أغسطس|سبتمبر|أكتوبر|نوفمبر|ديسمبر",
"short_months": "يناير|فبراير|مارس|أبريل|مايو|يونيو|يوليو|أغسطس|سبتمبر|أكتوبر|نوفمبر|ديسمبر",
"weeks": "الأحد|الإثنين|الثلاثاء|الأربعاء|الخميس|الجمعة|السبت",
"short_weeks": "أحد|إثنين|ثلاثاء|أربعاء|خميس|جمعة|سبت",
"seasons": "الربيع|الصيف|الخريف|الشتاء",
"constellations": "الحمل|الثور|الجوزاء|السرطان|الأسد|العذراء|الميزان|العقرب|القوس|الجدي|الدلو|الحوت",
"year": "1 سنة|%d سنوات",
"month": "1 شهر|%d أشهر",
"week": "1 أسبوع|%d أسابيع",
"day": "1 يوم|%d أيام",
"hour": "1 ساعة|%d ساعات",
"minute": "1 دقيقة|%d دقائق",
"second": "1 ثانية|%d ثواني",
"now": "الآن",
"ago": "%s مضت",
"from_now": "من %s",
"before": "%s قبل",
"after": "%s بعد"
}

22
vendor/github.com/dromara/carbon/v2/lang/bg.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Bulgarian",
"author": "yuksbg",
"months": "Януари|Февруари|Март|Април|Май|Юни|Юли|Август|Септември|Октомври|Ноември|Декември",
"short_months": "Ян|Фев|Март|Апр|Май|Юни|Юли|Авг|Сеп|Окт|Ноем|Дек",
"weeks": "Неделя|Понеделник|Вторник|Сряда|Четвъртък|Петък|Събота",
"short_weeks": "Нд|Пн|Вт|Ср|Чт|Пт|Сб",
"seasons": "Пролет|Лято|Есен|Зима",
"constellations": "Овен|Телец|Близнаци|Рак|Лъв|Дева|Везни|Скорпион|Стрелец|Козирог|Водолей|Риби",
"year": "1 година|%d години",
"month": "1 месец|%d месеца",
"week": "1 седмица|%d седмици",
"day": "1 ден|%d дни",
"hour": "1 час|%d часа",
"minute": "1 минута|%d минути",
"second": "1 секунда|%d секунди",
"now": "в момента",
"ago": "%s преди",
"from_now": "%s от сега",
"before": "%s преди",
"after": "%s след"
}

22
vendor/github.com/dromara/carbon/v2/lang/de.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "German",
"author": "benzammour",
"months": "Januar|Februar|März|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember",
"short_months": "Jan|Feb|Mär|Apr|Mai|Jun|Jul|Aug|Sep|Okt|Nov|Dez",
"weeks": "Sonntag|Montag|Dienstag|Mittwoch|Donnerstag|Freitag|Samstag",
"short_weeks": "So|Mo|Di|Mi|Do|Fr|Sa",
"seasons": "Frühling|Sommer|Herbst|Winter",
"constellations": "Widder|Stier|Zwilling|Krebs|Löwe|Jungfrau|Waage|Skorpion|Schütze|Steinbock|Wassermann|Fisch",
"year": "1 Jahr|%d Jahre",
"month": "1 Monat|%d Monate",
"week": "1 Woche|%d Wochen",
"day": "1 Tag|%d Tage",
"hour": "1 Stunde|%d Stunden",
"minute": "1 Minute|%d Minuten",
"second": "1 Sekunde|%d Sekunden",
"now": "gerade eben",
"ago": "vor %s",
"from_now": "%s ab jetzt",
"before": "%s davor",
"after": "%s danach"
}

22
vendor/github.com/dromara/carbon/v2/lang/dk.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Dansk",
"author": "Munk91",
"months": "januar|februar|marts|april|maj|juni|juli|august|september|oktober|november|december",
"short_months": "jan|feb|mar|apr|maj|jun|jul|aug|sep|okt|nov|dec",
"weeks": "søndag|mandag|tirsdag|onsdag|torsdag|fredag|lørdag",
"short_weeks": "søn|man|tir|ons|tor|fre|lør",
"seasons": "forår|sommer|efterår|vinter",
"constellations": "vædder|tyr|tvilling|krebs|løve|jomfru|vægt|skorpion|skytte|stenbuk|vandmand|fisk",
"year": "1 år|%d år",
"month": "1 måned|%d måneder",
"week": "1 uge|%d uger",
"day": "1 dag|%d dage",
"hour": "1 time|%d timer",
"minute": "1 minut|%d minutter",
"second": "1 sekund|%d sekunder",
"now": "lige nu",
"ago": "%s siden",
"from_now": "om %s",
"before": "%s før",
"after": "%s efter"
}

22
vendor/github.com/dromara/carbon/v2/lang/en.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "English",
"author": "gouguoyin",
"months": "January|February|March|April|May|June|July|August|September|October|November|December",
"short_months": "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",
"weeks": "Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday",
"short_weeks": "Sun|Mon|Tue|Wed|Thu|Fri|Sat",
"seasons": "Spring|Summer|Autumn|Winter",
"constellations": "Aries|Taurus|Gemini|Cancer|Leo|Virgo|Libra|Scorpio|Sagittarius|Capricorn|Aquarius|Pisces",
"year": "1 year|%d years",
"month": "1 month|%d months",
"week": "1 week|%d weeks",
"day": "1 day|%d days",
"hour": "1 hour|%d hours",
"minute": "1 minute|%d minutes",
"second": "1 second|%d seconds",
"now": "just now",
"ago": "%s ago",
"from_now": "%s from now",
"before": "%s before",
"after": "%s after"
}

22
vendor/github.com/dromara/carbon/v2/lang/es.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Spanish",
"author": "hgisinger",
"months": "Enero|Febrero|Marzo|Abril|Mayo|Junio|Julio|Agosto|Septiembre|Octubre|Noviembre|Diciembre",
"short_months": "Ene|Feb|Mar|Abr|May|Jun|Jul|Ago|Sep|Oct|Nov|Dic",
"weeks": "Domingo|Lunes|Martes|Miércoles|Jueves|Viernes|Sábado",
"short_weeks": "Dom|Lun|Mar|Mie|Jue|Vie|Sab",
"seasons": "Primavera|Verano|Otoño|Invierno",
"constellations": "Aries|Tauro|Geminis|Cancer|Leo|Virgo|Libra|Escorpio|Sagitario|Capricornio|Acuario|Piscis",
"year": "1 año|%d años",
"month": "1 mes|%d meses",
"week": "1 semana|%d semanas",
"day": "1 día|%d días",
"hour": "1 hora|%d horas",
"minute": "1 minuto|%d minutos",
"second": "1 segundo|%d segundos",
"now": "ahora",
"ago": "hace %s",
"from_now": "%s desde ahora",
"before": "%s antes",
"after": "%s después"
}

22
vendor/github.com/dromara/carbon/v2/lang/fa.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Farsi",
"author": "erfanMomeniii",
"months": "ژانویه|فوریه|مارس|آوریل|مه|ژوئن|ژوئیه|اوت|سپتامبر|اکتبر|نوامبر|دسامبر",
"short_months": "ژانویه|فوریه|مارس|آوریل|مه|ژوئن|ژوئیه|اوت|سپتامبر|اکتبر|نوامبر|دسامبر",
"weeks": "یکشنبه|دوشنبه|سه‌شنبه|چهارشنبه|پنجشنبه|جمعه|شنبه",
"short_weeks": "یکشنبه|دوشنبه|سه‌شنبه|چهارشنبه|پنجشنبه|جمعه|شنبه",
"seasons": "بهار|تابستان|پاییز|زمستان",
"constellations": "قوچ|گاو نر|دو پیکر|خرچنگ|شیر|خوشه|ترازو|عقرب|کماندار|بز|آبریز|ماهی",
"year": "1 سال|%d سال",
"month": "1 ماه|%d ماه",
"week": "1 هفته|%d هفته",
"day": "1 روز|%d روز",
"hour": "1 ساعت|%d ساعت",
"minute": "1 دقیقه|%d دقیقه",
"second": "1 ثانیه|%d ثانیه",
"now": "همین الان",
"ago": "%s پیش",
"from_now": "در %s",
"before": "%s قبل",
"after": "%s بعد"
}

22
vendor/github.com/dromara/carbon/v2/lang/fr.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "French",
"author": "hollowaykeanho",
"months": "Janvier|Février|Mars|Avril|Mai|Juin|Juillet|Août|Septembre|Octobre|Novembre|Décembre",
"short_months": "Janv|Févr|Mars|Avril|Mai|Juin|Juil|Août|Sept|Oct|Nov|Déc",
"weeks": "Dimanche|Lundi|Mardi|Mercredi|Jeudi|Vendredi|Samedi",
"short_weeks": "Dim|Lun|Mar|Mer|Jeu|Ven|Sam",
"seasons": "Le Printemps|L’été|L’Automne|L’Hiver",
"constellations": "Bélier|Taureau|Gémeaux|Cancer|Lion|Vierge|Balance|Scorpion|Sagittaire|Capricorne|Verseau|Poissons",
"year": "1 an|%d ans",
"month": "1 mois|%d mois",
"week": "1 semaine|%d semaines",
"day": "1 jour|%d jours",
"hour": "1 heure|%d heures",
"minute": "1 minute|%d minutes",
"second": "1 seconde|%d secondes",
"now": "maintenant",
"ago": "il y a %s",
"from_now": "%s à partir de maintenant",
"before": "avant %s",
"after": "après %s"
}

22
vendor/github.com/dromara/carbon/v2/lang/hi.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Hindi",
"author": "chauhan17nitin",
"months": "जनवरी|फ़रवरी|मार्च|अप्रैल|मई|जून|जुलाई|अगस्त|सितंबर|अक्टूबर|नवंबर|दिसंबर",
"short_months": "जन|फ़र|मार्च|अप्रैल|मई|जून|जुलाई|अगस्त|सितंबर|अक्टूबर|नवंबर|दिसंबर",
"weeks": "रविवार|सोमवार|मंगलवार|बुधवार|गुरुवार|शुक्रवार|शनिवार",
"short_weeks": "रवि|सोम|मंगल|बुध|गुरु|शुक्र|शनि",
"seasons": "वसंत|ग्रीष्म|पतझड़|शीत",
"constellations": "मेष|वृषभ|मिथुन|कर्क|सिंह|कन्या|तुला|वृश्चिक|धनु|मकर|कुंभ|मीन",
"year": "1 वर्ष|%d वर्ष",
"month": "1 महीना|%d महीने",
"week": "1 सप्ताह|%d सप्ताह",
"day": "1 दिन|%d दिन",
"hour": "1 घंटा|%d घंटे",
"minute": "1 मिनट|%d मिनट",
"second": "1 सेकंड|%d सेकंड",
"now": "अभी",
"ago": "%s पहले",
"from_now": "%s बाद",
"before": "%s पहले",
"after": "%s बाद"
}

22
vendor/github.com/dromara/carbon/v2/lang/hu.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Hungarian",
"author": "kenlas",
"months": "január|február|március|április|május|június|július|augusztus|szeptember|október|november|december",
"short_months": "jan.|febr.|márc.|ápr.|máj.|jún.|júl.|aug.|szept.|okt.|nov.|dec.",
"weeks": "Vasárnap|Hétfő|Kedd|Szerda|Csütörtök|Péntek|Szombat",
"short_weeks": "Vas|Hét|Ke|Sze|Csü|Pé|Szo",
"seasons": "Tavasz|Nyár|Ősz|Tél",
"constellations": "Kos|Bika|Ikrek|Rák|Oroszlán|Szűz|Mérleg|Skorpió|Nyilas|Bak|Vízöntő|Halak",
"year": "1 év|%d év",
"month": "1 hónap|%d hónap",
"week": "1 hét|%d hét",
"day": "1 nap|%d nap",
"hour": "1 óra|%d óra",
"minute": "1 perc|%d perc",
"second": "1 másodperc|%d másodperc",
"now": "most",
"ago": "%s",
"from_now": "%s múlva",
"before": "%s korábban",
"after": "%s később"
}

22
vendor/github.com/dromara/carbon/v2/lang/id.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Indonesian",
"author": "justpoypoy",
"months": "Januari|Februari|Maret|April|Mei|Juni|Juli|Agustus|September|Oktober|November|Desember",
"short_months": "Jan|Feb|Mar|Apr|Mei|Jun|Jul|Agt|Sep|Okt|Nov|Des",
"weeks": "Minggu|Senin|Selasa|Rabu|Kamis|Jumaat|Sabtu",
"short_weeks": "Min|Sen|Sel|Rab|Kam|Jum|Sab",
"seasons": "Musim Semi|Musim Panas|Musim Gugur|Musim Salju",
"constellations": "Aries|Taurus|Gemini|Cancer|Leo|Virgo|Libra|Scorpio|Sagitarius|Capricorn|Aquarius|Pisces",
"year": "1 tahun|%d tahun",
"month": "1 bulan|%d bulan",
"week": "1 minggu|%d minggu",
"day": "1 hari|%d hari",
"hour": "1 jam|%d jam",
"minute": "1 menit|%d menit",
"second": "1 detik|%d detik",
"now": "baru saja",
"ago": "%s yang lalu",
"from_now": "%s dari sekarang",
"before": "%s sebelum",
"after": "%s sesudah"
}

21
vendor/github.com/dromara/carbon/v2/lang/it.json generated vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "Italian",
"author": "nicoloHevelop",
"months": "Gennaio|Febbraio|Marzo|Aprile|Maggio|Giugno|Luglio|Agosto|Settembre|Ottobre|Novembre|Dicembre",
"short_months": "Gen|Feb|Mar|Apr|Mag|Giu|Lug|Ago|Set|Ott|Nov|Dic",
"weeks": "Domenica|Lunedí|Martedí|Mercoledí|Giovedí|Venerdí|Sabato",
"short_weeks": "Dom|Lun|Mar|Mer|Gio|Ven|Sab",
"seasons": "Primavera|Estate|Autunno|Inverno",
"year": "1 anno|%d anni",
"month": "1 mese|%d mesi",
"week": "1 settimana|%d settimane",
"day": "1 giorno|%d giorni",
"hour": "1 ora|%d ore",
"minute": "1 minuto|%d minuti",
"second": "1 secondo|%d secondi",
"now": "proprio ora",
"ago": "%s fa",
"from_now": "%s da adesso",
"before": "%s prima",
"after": "%s dopo"
}

22
vendor/github.com/dromara/carbon/v2/lang/jp.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Japanese",
"author": "gouguoyin",
"months": "1月|2月|3月|4月|5月|6月|7月|8月|9月|10月|11月|12月",
"short_months": "1月|2月|3月|4月|5月|6月|7月|8月|9月|10月|11月|12月",
"weeks": "日曜日|月曜日|火曜日|水曜日|木曜日|金曜日|土曜日",
"short_weeks": "日|月|火|水|木|金|土",
"seasons": "春|夏|秋|冬",
"constellations": "おひつじ座|おうし座|ふたご座|かに座|しし座|おとめ座|てんびん座|さそり座|いて座|やぎ座|みずがめ座|うお座",
"year": "%d 年",
"month": "%d ヶ月",
"week": "%d 週間",
"day": "%d 日",
"hour": "%d 時間",
"minute": "%d 分",
"second": "%d 秒",
"now": "現在",
"ago": "%s前",
"from_now": "%s後",
"before": "%s前",
"after": "%s後"
}

22
vendor/github.com/dromara/carbon/v2/lang/kr.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Korean",
"author": "nannul",
"months": "일월|이월|삼월|사월|오월|유월|칠월|팔월|구월|시월|십일월|십이월",
"short_months": "1월|2월|3월|4월|5월|6월|7월|8월|9월|10월|11월|12월",
"weeks": "일요일|월요일|화요일|수요일|목요일|금요일|토요일",
"short_weeks": "일요일|월요일|화요일|수요일|목요일|금요일|토요일",
"seasons": "봄|여름|가을|겨울",
"constellations": "양자리|황소자리|쌍둥이자리|게자리|사자자리|처녀자리|천칭자리|전갈자리|사수자리|염소자리|물병자리|물고기자리",
"year": "%d 년",
"month": "%d 개월",
"week": "%d 주",
"day": "%d 일",
"hour": "%d 시간",
"minute": "%d 분",
"second": "%d 초",
"now": "방금",
"ago": "%s앞",
"from_now": "%s후",
"before": "%s전",
"after": "%s후"
}

22
vendor/github.com/dromara/carbon/v2/lang/ms-MY.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Bahasa Malaysia",
"author": "hollowaykeanho",
"months": "Januari|Februari|Mac|April|Mei|Jun|Julai|Ogos|September|Oktober|November|Disember",
"short_months": "Jan|Feb|Mac|Apr|Mei|Jun|Jul|Ogs|Sep|Okt|Nov|Dis",
"weeks": "Ahad|Isnin|Selasa|Rabu|Khamis|Jumaat|Sabtu",
"short_weeks": "Ahd|Isn|Sel|Rab|Kha|Jum|Sab",
"seasons": "Musim Bunga|Musim Panas|Musim Luruh|Musim Sejuk",
"constellations": "Aries|Taurus|Gemini|Cancer|Leo|Virgo|Libra|Scorpio|Sagittarius|Capricorn|Aquarius|Pisces",
"year": "1 tahun|%d tahun",
"month": "1 bulan|%d bulan",
"week": "1 minggu|%d minggu",
"day": "1 hari|%d hari",
"hour": "1 jam|%d jam",
"minute": "1 minit|%d minit",
"second": "1 saat|%d saat",
"now": "baru tadi",
"ago": "%s lalu",
"from_now": "%s dari sekarang",
"before": "sebelum %s",
"after": "selepas %s"
}

21
vendor/github.com/dromara/carbon/v2/lang/nb.json generated vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"name": "Norsk bokmål",
"months": "januar|februar|mars|april|mai|juni|juli|august|september|oktober|november|desember",
"short_months": "jan|feb|mar|apr|mai|jun|jul|aug|sep|okt|nov|des",
"weeks": "søndag|mandag|tirsdag|onsdag|torsdag|fredag|lørdag",
"short_weeks": "søn|man|tir|ons|tor|fre|lør",
"seasons": "vår|sommer|høst|vinter",
"constellations": "vær|tyr|tvilling|kreps|løve|jomfru|vekt|skorpion|skytten|steinbukk|vannmann|fisk",
"year": "1 år|%d år",
"month": "1 måned|%d måneder",
"week": "1 uke|%d uker",
"day": "1 dag|%d dager",
"hour": "1 time|%d timer",
"minute": "1 minutt|%d minutter",
"second": "1 sekund|%d sekunder",
"now": "nå nettopp",
"ago": "%s siden",
"from_now": "om %s",
"before": "%s før",
"after": "%s etter"
}

22
vendor/github.com/dromara/carbon/v2/lang/nl.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Dutch",
"author": "RemcoE33",
"months": "januari|februari|maart|april|mei|juni|juli|augustus|september|oktober|november|december",
"short_months": "jan|feb|mrt|apr|mei|jun|jul|aug|sep|okt|nov|dec",
"weeks": "Zondag|Maandag|Dinsdag|Woensdag|Donderdag|Vrijdag|Zaterdag|Zondag",
"short_weeks": "zo|ma|di|wo|do|vr|za",
"seasons": "Lente|Zomer|Herfst|Winter",
"constellations": "Ram|Stier|Tweelingen|Kreeft|Leeuw|Maagd|Weegschaal|Schorpioen|Boogschutter|Steenbok|Waterman|Vissen",
"year": "1 jaar|%d jaren",
"month": "1 maand|%d maanden",
"week": "1 week|%d weken",
"day": "1 dag|%d dagen",
"hour": "1 uur|%d uren",
"minute": "1 minuut|%d minuten",
"second": "1 seconde|%d seconden",
"now": "zojuist",
"ago": "%s geleden",
"from_now": "%s vanaf nu",
"before": "%s voor",
"after": "%s na"
}

22
vendor/github.com/dromara/carbon/v2/lang/pl.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Polish",
"author": "gouguoyin",
"months": "stycznia|lutego|marca|kwietnia|maja|czerwca|lipca|sierpnia|września|października|listopada|grudnia",
"short_months": "sty|lut|mar|kwi|maj|cze|lip|sie|wrz|paź|lis|gru",
"weeks": "niedziela|poniedziałek|wtorek|środa|czwartek|piątek|sobota",
"short_weeks": "ndz|pon|wt|śr|czw|pt|sob",
"seasons": "sprężyna|lato|jesień|zima",
"constellations": "baran|byk|bliźnięta|rak|lew|dziewica|waga|skorpion|strzelec|koziorożec|wodnik|ryby",
"year": "1 rok|2 lata|%d lat",
"month": "1 miesiąc|2 miesiące|%d miesięcy",
"week": "1 tydzień|2 tygodnie|%d tygodni",
"day": "1 dzień|%d dni",
"hour": "1 godzina|2 godziny|%d godzin",
"minute": "1 minuta|2 minuty|%d minut",
"second": "1 sekunda|2 sekundy|%d sekund",
"now": "teraz",
"ago": "%s temu",
"from_now": "%s po",
"before": "%s przed",
"after": "%s po"
}

22
vendor/github.com/dromara/carbon/v2/lang/pt.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Portuguese",
"author": "felipear89",
"months": "Janeiro|Fevereiro|Março|Abril|Maio|Junho|Julho|Agosto|Setembro|Outubro|Novembro|Dezembro",
"short_months": "Jan|Fev|Mar|Abr|Maio|Jun|Jul|Ago|Set|Out|Nov|Dez",
"weeks": "Domingo|Segunda-feira|Terça-feira|Quarta-feira|Quinta-feira|Sexta-feira|Sábado",
"short_weeks": "Dom|Seg|Ter|Qua|Qui|Sex|Sab",
"seasons": "Primavera|Verão|Outono|Inverno",
"constellations": "Áries|Touro|Gêmeos|Câncer|Leão|Virgem|Libra|Escorpião|Sagitário|Capricórnio|Aquário|Peixes",
"year": "1 ano|%d anos",
"month": "1 mês|%d meses",
"week": "1 semana|%d semanas",
"day": "1 dia|%d dias",
"hour": "1 hora|%d horas",
"minute": "1 minuto|%d minutos",
"second": "1 segundo|%d segundos",
"now": "agora",
"ago": "%s atrás",
"from_now": "%s a partir de agora",
"before": "%s antes",
"after": "%s depois"
}

22
vendor/github.com/dromara/carbon/v2/lang/ro.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Romanian",
"author": "DrOctavius",
"months": "Ianuarie|Februarie|Martie|Aprilie|Mai|Iunie|Iulie|August|Septembrie|Octombrie|Noiembrie|Decembrie",
"short_months": "Ian|Feb|Mar|Apr|Mai|Iun|Iul|Aug|Sep|Oct|Noi|Dec",
"weeks": "Duminică|Luni|Marți|Miercuri|Joi|Vineri|Sîmbătă",
"short_weeks": "Dum|Lun|Mar|Mie|Joi|Vin|Sîm",
"seasons": "Primăvara|Vara|Toamna|Iarna",
"constellations": "Berbec|Taur|Gemeni|Rac|Leu|Fecioară|Balanță|Scorpion|Săgetător|Capricorn|Vărsător|Pești",
"year": "1 an|%d ani",
"month": "1 lună|%d luni",
"week": "1 săptămînă|%d săptămîni",
"day": "1 zi|%d zile",
"hour": "1 oră|%d ore",
"minute": "1 minută|%d minute",
"second": "1 secundă|%d secunde",
"now": "chiar acum",
"ago": "%s în urmă",
"from_now": "%s de acum",
"before": "%s înainte",
"after": "%s după"
}

22
vendor/github.com/dromara/carbon/v2/lang/ru.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Russian",
"author": "zemlyak",
"months": "Январь|Февраль|Март|Апрель|Май|Июнь|Июль|Август|Сентябрь|Октябрь|Ноябрь|Декабрь",
"short_months": "Янв|Фев|Мар|Апр|Май|Июн|Июл|Авг|Сен|Окт|Ноя|Дек",
"weeks": "Воскресенье|Понедельник|Вторник|Среда|Четверг|Пятница|Суббота",
"short_weeks": "Вс|Пн|Вт|Ср|Чт|Пт|Сб",
"seasons": "Весна|Лето|Осень|Зима",
"constellations": "Овен|Телец|Близнецы|Рак|Лев|Дева|Весы|Скорпион|Стрелец|Козерог|Водолей|Рыбы",
"year": "1 год|2 года|3 года|4 года|%d лет",
"month": "1 месяц|2 месяца|3 месяца|4 месяца|%d месяцев",
"week": "1 неделя|2 недели|3 недели|4 недели|%d недель",
"day": "1 день|2 дня|3 дня|4 дня|%d дней",
"hour": "1 час|2 часа|3 часа|4 часа|%d часов",
"minute": "1 минуту|2 минуты|3 минуты|4 минуты|%d минут",
"second": "1 секунда|2 секунды|3 секунды|4 секунды|%d секунд",
"now": "сейчас",
"ago": "%s назад",
"from_now": "через %s",
"before": "за %s до",
"after": "через %s после"
}

22
vendor/github.com/dromara/carbon/v2/lang/se.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Swedish",
"author": "jwanglof",
"months": "Januari|Februari|Mars|April|Maj|Juni|Juli|Augusti|September|Oktober|November|December",
"short_months": "Jan|Feb|Mars|April|Maj|Juni|Juli|Aug|Sep|Okt|Nov|Dec",
"weeks": "Söndag|Måndag|Tisdag|Onsdag|Torsdag|Fredag|Lördag",
"short_weeks": "Sön|Mån|Tis|Ons|Tors|Fre|Lör",
"seasons": "Vår|Sommar|Höst|Vinter",
"constellations": "Väduren|Oxen|Tvillingarna|Kräftan|Lejonet|Jungfrun|Vågen|Skorpionen|Skytten|Stenbocken|Vattumannen|Fiskarna",
"year": "1 år|%d år",
"month": "1 månad|%d månader",
"week": "1 vecka|%d veckor",
"day": "1 dag|%d dagar",
"hour": "1 timme|%d timmar",
"minute": "1 minut|%d minuter",
"second": "1 sekund|%d sekunder",
"now": "just nu",
"ago": "%s sedan",
"from_now": "%s fr.o.m. nu",
"before": "%s innan",
"after": "%s efter"
}

22
vendor/github.com/dromara/carbon/v2/lang/th.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Thailand",
"author": "izcream",
"months": "มกราคม|กุมภาพันธ์|มีนาคม|เมษายน|พฤษภาคม|มิถุนายน|กรกฎาคม|สิงหาคม|กันยายน|ตุลาคม|พฤศจิกายน|ธันวาคม",
"short_months": "ม.ค.|ก.พ.|มี.ค.|เม.ย.|พ.ค.|มิ.ย.|ก.ค.|ส.ค.|ก.ย.|ต.ค.|พ.ย.|ธ.ค.",
"weeks": "อาทิตย์|จันทร์|อังคาร|พุธ|พฤหัสบดี|ศุกร์|เสาร์",
"short_weeks": "อา.|จ.|อัง.|พ.|พฤ.|ศ.|ส.",
"seasons": "ฤดูใบไม้ผลิ|ฤดูร้อน|ฤดูใบไม้ร่วง|ฤดูหนาว",
"constellations": "เมษ|พฤษภ|เมถุน|กรกฎ|สิงห์|กันย์|ตุลย์|พิจิก|ธนู|มังกร|กุมภ์|มีน",
"year": "1 ปี|%d ปี",
"month": "1 เดือน|%d เดือน",
"week": "1 สัปดาห์|%d สัปดาห์",
"day": "1 วัน|%d วัน",
"hour": "1 ชั่วโมง|%d ชั่วโมง",
"minute": "1 นาที|%d นาที",
"second": "1 วินาที|%d วินาที",
"now": "ไม่กี่วินาทีที่แล้ว",
"ago": "%s ที่แล้ว",
"from_now": "อีก %s",
"before": "%s ก่อน",
"after": "%s หลังจากนี้"
}

22
vendor/github.com/dromara/carbon/v2/lang/tr.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Turkish",
"author": "emresenyuva",
"months": "Ocak|Şubat|Mart|Nisan|Mayıs|Haziran|Temmuz|Ağustos|Eylül|Ekim|Kasım|Aralık",
"short_months": "Oca|Şub|Mar|Nis|May|Haz|Tem|Ağu|Eyl|Eki|Kas|Ara",
"weeks": "Pazar|Pazartesi|Salı|Çarşamba|Perşembe|Cuma|Cumartesi",
"short_weeks": "Paz|Pts|Sal|Çrş|Per|Cum|Cts",
"seasons": "İlkbahar|Yaz|Sonbahar|Kış",
"constellations": "Koç|Boğa|İkizler|Yengeç|Aslan|Başak|Terazi|Akrep|Yay|Oğlak|Kova|Balık",
"year": "bir yıl|%d yıl",
"month": "bir ay|%d ay",
"week": "bir hafta|%d hafta",
"day": "bir gün|%d gün",
"hour": "bir saat|%d saat",
"minute": "bir dakika|%d dakika",
"second": "bir saniye|%d saniye",
"now": "az önce",
"ago": "%s evvel",
"from_now": "şu andan itibaren %s sonra",
"before": "%s önce",
"after": "%s sonra"
}

22
vendor/github.com/dromara/carbon/v2/lang/uk.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Ukrainian",
"author": "zumoshi",
"months": "січня|лютого|березня|квітня|травня|червня|липня|серпня|вересня|жовтня|листопада|грудня",
"short_months": "січ|лют|бер|квіт|трав|черв|лип|серп|вер|жовт|лист|груд",
"weeks": "неділя|понеділок|вівторок|середа|четвер|п’ятниця|субота",
"short_weeks": "ндл|пнд|втр|срд|чтв|птн|сбт",
"seasons": "Весна|Літо|Осінь|Зима",
"constellations": "Овен|Телець|Близнюки|Рак|Лев|Діва|Терези|Скорпіон|Стрілець|Козоріг|Водолій|Риби",
"year": "рік|2 роки|3 роки|4 роки|%d років",
"month": "місяць|2 місяці|3 місяці|4 місяці|%d місяців",
"week": "tиждень|2 тижні|3 тижні|4 тижні|%d тижнів",
"day": "день|2 дні|3 дні|4 дні|%d днів",
"hour": "1 година|2 години|3 години|4 години|%d годин",
"minute": "1 хвилина|2 хвилини|3 хвилини|4 хвилини|%d хвилин",
"second": "1 секунда|2 секунди|3 секунди|4 секунди|%d секунд",
"now": "зараз",
"ago": "%s тому",
"from_now": "за %s",
"before": "%s до",
"after": "%s після"
}

22
vendor/github.com/dromara/carbon/v2/lang/vi.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "VietNamese",
"author": "culy247",
"months": "Tháng Một|Tháng Hai|Tháng Ba|Tháng Tư|Tháng Năm|Tháng Sáu|Tháng Bảy|Tháng Tám|Tháng Chín|Tháng Mười|Tháng Mười Một|Tháng Mười Hai",
"short_months": "Giêng|Hai|Ba|Bốn|Năm|Sáu|Bảy|Tám|Chìn|Mười|Một|Chạp",
"weeks": "Chủ Nhật|Thứ Hai|Thứ Ba|Thứ Tư|Thứ Năm|Thứ Sáu|Thứ Bảy",
"short_weeks": "CN|Hai|Ba|Tư|Năm|Sáu|Bảy",
"seasons": "Xuân|Hè|Thu|Đông",
"constellations": "Bạch Dương|Kim Ngưu|Song Tử|Cự Giải|Sư Tử|Xử Nữ|Thiên Bình|Bọ Cạp|Nhân Mã|Ma Kết|Bảo Bình|Song Ngư",
"year": "%d năm",
"month": "%d tháng",
"week": "%d tuần",
"day": "%d ngày",
"hour": "%d giờ",
"minute": "%d phút",
"second": "%d giây",
"now": "vừa xong",
"ago": "%s trước",
"from_now": "%s từ bây giờ",
"before": "%s trước",
"after": "%s sau"
}

22
vendor/github.com/dromara/carbon/v2/lang/zh-CN.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Simplified Chinese",
"author": "gouguoyin",
"months": "一月|二月|三月|四月|五月|六月|七月|八月|九月|十月|十一月|十二月",
"short_months": "1月|2月|3月|4月|5月|6月|7月|8月|9月|10月|11月|12月",
"weeks": "星期日|星期一|星期二|星期三|星期四|星期五|星期六",
"short_weeks": "周日|周一|周二|周三|周四|周五|周六",
"seasons": "春季|夏季|秋季|冬季",
"constellations": "白羊座|金牛座|双子座|巨蟹座|狮子座|处女座|天秤座|天蝎座|射手座|摩羯座|水瓶座|双鱼座",
"year": "%d 年",
"month": "%d 个月",
"week": "%d 周",
"day": "%d 天",
"hour": "%d 小时",
"minute": "%d 分钟",
"second": "%d 秒",
"now": "刚刚",
"ago": "%s前",
"from_now": "%s后",
"before": "%s前",
"after": "%s后"
}

22
vendor/github.com/dromara/carbon/v2/lang/zh-TW.json generated vendored Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Traditional Chinese",
"author": "gouguoyin",
"months": "一月|二月|三月|四月|五月|六月|七月|八月|九月|十月|十一月|十二月",
"short_months": "1月|2月|3月|4月|5月|6月|7月|8月|9月|10月|11月|12月",
"weeks": "星期日|星期一|星期二|星期三|星期四|星期五|星期六",
"short_weeks": "週日|週一|週二|週三|週四|週五|週六",
"seasons": "春季|夏季|秋季|冬季",
"constellations": "白羊座|金牛座|雙子座|巨蟹座|獅子座|處女座|天秤座|天蠍座|射手座|摩羯座|水瓶座|雙魚座",
"year": "%d 年",
"month": "%d 個月",
"week": "%d 週",
"day": "%d 天",
"hour": "%d 小時",
"minute": "%d 分鐘",
"second": "%d 秒",
"now": "剛剛",
"ago": "%s前",
"from_now": "%s後",
"before": "%s前",
"after": "%s後"
}

136
vendor/github.com/dromara/carbon/v2/language.go generated vendored Normal file
View File

@@ -0,0 +1,136 @@
package carbon
import (
"embed"
"encoding/json"
"fmt"
"strconv"
"strings"
"sync"
)
//go:embed lang
var fs embed.FS
var (
// empty locale error
// 空区域错误
emptyLocaleError = func() error {
return fmt.Errorf("locale cannot be empty")
}
// invalid locale error
// 无效的区域错误
invalidLocaleError = func(locale string) error {
return fmt.Errorf("invalid locale file %q, please make sure the json file exists and is valid", locale)
}
// invalid resources error
// 无效的资源错误
invalidResourcesError = func() error {
return fmt.Errorf("invalid resources, please make sure the resources exists and is valid")
}
)
// Language defines a Language struct.
// 定义 Language 结构体
type Language struct {
dir string
locale string
resources map[string]string
Error error
rw *sync.RWMutex
}
// NewLanguage returns a new Language instance.
// 初始化 Language 结构体
func NewLanguage() *Language {
return &Language{
dir: "lang/",
locale: DefaultLocale,
resources: make(map[string]string),
rw: new(sync.RWMutex),
}
}
// SetLocale sets language locale.
// 设置区域
func (lang *Language) SetLocale(locale string) *Language {
if lang == nil || lang.Error != nil {
return lang
}
if locale == "" {
lang.Error = emptyLocaleError()
return lang
}
lang.rw.Lock()
defer lang.rw.Unlock()
lang.locale = locale
fileName := lang.dir + locale + ".json"
bytes, err := fs.ReadFile(fileName)
if err != nil {
lang.Error = invalidLocaleError(fileName)
return lang
}
_ = json.Unmarshal(bytes, &lang.resources)
return lang
}
// SetResources sets language resources.
// 设置资源
func (lang *Language) SetResources(resources map[string]string) *Language {
if lang == nil || lang.Error != nil {
return lang
}
if resources == nil {
lang.Error = invalidResourcesError()
return lang
}
lang.rw.Lock()
defer lang.rw.Unlock()
if len(lang.resources) == 0 {
lang.resources = resources
return lang
}
for k, v := range resources {
if _, ok := lang.resources[k]; ok {
lang.resources[k] = v
}
}
return lang
}
// returns a translated string.
// 翻译转换
func (lang *Language) translate(unit string, value int64) string {
if lang == nil || lang.resources == nil {
return ""
}
lang.rw.Lock()
defer lang.rw.Unlock()
if len(lang.resources) == 0 {
lang.rw.Unlock()
lang.SetLocale(DefaultLocale)
lang.rw.Lock()
}
slice := strings.Split(lang.resources[unit], "|")
number := getAbsValue(value)
if len(slice) == 1 {
return strings.Replace(slice[0], "%d", strconv.FormatInt(value, 10), 1)
}
if int64(len(slice)) <= number {
return strings.Replace(slice[len(slice)-1], "%d", strconv.FormatInt(value, 10), 1)
}
if !strings.Contains(slice[number-1], "%d") && value < 0 {
return "-" + slice[number-1]
}
return strings.Replace(slice[number-1], "%d", strconv.FormatInt(value, 10), 1)
}

885
vendor/github.com/dromara/carbon/v2/outputer.go generated vendored Normal file
View File

@@ -0,0 +1,885 @@
package carbon
import (
"bytes"
"fmt"
"strconv"
"strings"
)
// String implements the interface Stringer for Carbon struct.
// 实现 Stringer 接口
func (c *Carbon) String() string {
if c.IsInvalid() {
return ""
}
return c.Layout(c.layout, c.Timezone())
}
// GoString implements fmt.GoStringer and formats c to be printed in Go source code.
// 实现 fmt.GoStringer 接口,并格式化 c 以在 Go 源代码中打印
func (c *Carbon) GoString() string {
if c.IsInvalid() {
return ""
}
return c.StdTime().GoString()
}
// ToString outputs a string in "2006-01-02 15:04:05.999999999 -0700 MST" layout.
// 输出 "2006-01-02 15:04:05.999999999 -0700 MST" 格式字符串
func (c *Carbon) ToString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().String()
}
// ToMonthString outputs a string in month layout like "January", i18n is supported.
// 输出完整月份字符串,支持 i18n
func (c *Carbon) ToMonthString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
if len(c.lang.resources) == 0 {
c.lang.SetLocale(DefaultLocale)
}
c.lang.rw.RLock()
defer c.lang.rw.RUnlock()
if resources, ok := c.lang.resources["months"]; ok {
slice := strings.Split(resources, "|")
if len(slice) == MonthsPerYear {
return slice[c.Month()-1]
}
}
return ""
}
// ToShortMonthString outputs a string in short month layout like "Jan", i18n is supported.
// 输出缩写月份字符串,支持 i18n
func (c *Carbon) ToShortMonthString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
if len(c.lang.resources) == 0 {
c.lang.SetLocale(DefaultLocale)
}
c.lang.rw.RLock()
defer c.lang.rw.RUnlock()
if resources, ok := c.lang.resources["short_months"]; ok {
slice := strings.Split(resources, "|")
if len(slice) == MonthsPerYear {
return slice[c.Month()-1]
}
}
return ""
}
// ToWeekString outputs a string in week layout like "Sunday", i18n is supported.
// 输出完整星期字符串,支持 i18n
func (c *Carbon) ToWeekString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
if len(c.lang.resources) == 0 {
c.lang.SetLocale(DefaultLocale)
}
c.lang.rw.RLock()
defer c.lang.rw.RUnlock()
if resources, ok := c.lang.resources["weeks"]; ok {
slice := strings.Split(resources, "|")
if len(slice) == DaysPerWeek {
return slice[c.DayOfWeek()%DaysPerWeek]
}
}
return ""
}
// ToShortWeekString outputs a string in short week layout like "Sun", i18n is supported.
// 输出缩写星期字符串,支持 i18n
func (c *Carbon) ToShortWeekString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
if len(c.lang.resources) == 0 {
c.lang.SetLocale(DefaultLocale)
}
c.lang.rw.RLock()
defer c.lang.rw.RUnlock()
if resources, ok := c.lang.resources["short_weeks"]; ok {
slice := strings.Split(resources, "|")
if len(slice) == DaysPerWeek {
return slice[c.DayOfWeek()%DaysPerWeek]
}
}
return ""
}
// ToDayDateTimeString outputs a string in "Mon, Jan 2, 2006 3:04 PM" layout.
// 输出 "Mon, Jan 2, 2006 3:04 PM" 格式字符串
func (c *Carbon) ToDayDateTimeString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DayDateTimeLayout)
}
// ToDateTimeString outputs a string in "2006-01-02 15:04:05" layout.
// 输出 "2006-01-02 15:04:05" 格式字符串
func (c *Carbon) ToDateTimeString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateTimeLayout)
}
// ToDateTimeMilliString outputs a string in "2006-01-02 15:04:05.999" layout.
// 输出 "2006-01-02 15:04:05.999" 格式字符串
func (c *Carbon) ToDateTimeMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateTimeMilliLayout)
}
// ToDateTimeMicroString outputs a string in "2006-01-02 15:04:05.999999" layout.
// 输出 "2006-01-02 15:04:05.999999" 格式字符串
func (c *Carbon) ToDateTimeMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateTimeMicroLayout)
}
// ToDateTimeNanoString outputs a string in "2006-01-02 15:04:05.999999999" layout.
// 输出 "2006-01-02 15:04:05.999999999" 格式字符串
func (c *Carbon) ToDateTimeNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateTimeNanoLayout)
}
// ToShortDateTimeString outputs a string in "20060102150405" layout.
// 输出 "20060102150405" 格式字符串
func (c *Carbon) ToShortDateTimeString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateTimeLayout)
}
// ToShortDateTimeMilliString outputs a string in "20060102150405.999" layout.
// 输出 "20060102150405.999" 格式字符串
func (c *Carbon) ToShortDateTimeMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateTimeMilliLayout)
}
// ToShortDateTimeMicroString outputs a string in "20060102150405.999999" layout.
// 输出 "20060102150405.999999" 格式字符串
func (c *Carbon) ToShortDateTimeMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateTimeMicroLayout)
}
// ToShortDateTimeNanoString outputs a string in "20060102150405.999999999" layout.
// 输出 "20060102150405.999999999" 格式字符串
func (c *Carbon) ToShortDateTimeNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateTimeNanoLayout)
}
// ToDateString outputs a string in "2006-01-02" layout.
// 输出 "2006-01-02" 格式字符串
func (c *Carbon) ToDateString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateLayout)
}
// ToDateMilliString outputs a string in "2006-01-02.999" layout.
// 输出 "2006-01-02.999" 格式字符串
func (c *Carbon) ToDateMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateMilliLayout)
}
// ToDateMicroString outputs a string in "2006-01-02.999999" layout.
// 输出 "2006-01-02.999999" 格式字符串
func (c *Carbon) ToDateMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateMicroLayout)
}
// ToDateNanoString outputs a string in "2006-01-02.999999999" layout.
// 输出 "2006-01-02.999999999" 格式字符串
func (c *Carbon) ToDateNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(DateNanoLayout)
}
// ToShortDateString outputs a string in "20060102" layout.
// 输出 "20060102" 格式字符串
func (c *Carbon) ToShortDateString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateLayout)
}
// ToShortDateMilliString outputs a string in "20060102.999" layout.
// 输出 "20060102.999" 格式字符串
func (c *Carbon) ToShortDateMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateMilliLayout)
}
// ToShortDateMicroString outputs a string in "20060102.999999" layout.
// 输出 "20060102.999999" 格式字符串
func (c *Carbon) ToShortDateMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateMicroLayout)
}
// ToShortDateNanoString outputs a string in "20060102.999999999" layout.
// 输出 "20060102.999999999" 格式字符串
func (c *Carbon) ToShortDateNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortDateNanoLayout)
}
// ToTimeString outputs a string in "15:04:05" layout.
// 输出 "15:04:05" 格式字符串
func (c *Carbon) ToTimeString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(TimeLayout)
}
// ToTimeMilliString outputs a string in "15:04:05.999" layout.
// 输出 "15:04:05.999" 格式字符串
func (c *Carbon) ToTimeMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(TimeMilliLayout)
}
// ToTimeMicroString outputs a string in "15:04:05.999999" layout.
// 输出 "15:04:05.999999" 格式字符串
func (c *Carbon) ToTimeMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(TimeMicroLayout)
}
// ToTimeNanoString outputs a string in "15:04:05.999999999" layout.
// 输出 "15:04:05.999999999" 格式字符串
func (c *Carbon) ToTimeNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(TimeNanoLayout)
}
// ToShortTimeString outputs a string in "150405" layout.
// 输出 "150405" 格式字符串
func (c *Carbon) ToShortTimeString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortTimeLayout)
}
// ToShortTimeMilliString outputs a string in "150405.999" layout.
// 输出 "150405.999" 格式字符串
func (c *Carbon) ToShortTimeMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortTimeMilliLayout)
}
// ToShortTimeMicroString outputs a string in "150405.999999" layout.
// 输出 "150405.999999" 格式字符串
func (c *Carbon) ToShortTimeMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortTimeMicroLayout)
}
// ToShortTimeNanoString outputs a string in "150405.999999999" layout.
// 输出 "150405.999999999" 格式字符串
func (c *Carbon) ToShortTimeNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ShortTimeNanoLayout)
}
// ToAtomString outputs a string in "2006-01-02T15:04:05Z07:00" layout.
// 输出 "2006-01-02T15:04:05Z07:00" 格式字符串
func (c *Carbon) ToAtomString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(AtomLayout)
}
// ToAnsicString outputs a string in "Mon Jan _2 15:04:05 2006" layout.
// 输出 "Mon Jan _2 15:04:05 2006" 格式字符串
func (c *Carbon) ToAnsicString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ANSICLayout)
}
// ToCookieString outputs a string in "Monday, 02-Jan-2006 15:04:05 MST" layout.
// 输出 "Monday, 02-Jan-2006 15:04:05 MST" 格式字符串
func (c *Carbon) ToCookieString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(CookieLayout)
}
// ToRssString outputs a string in "Mon, 02 Jan 2006 15:04:05 -0700" format.
// 输出 "Mon, 02 Jan 2006 15:04:05 -0700" 格式字符串
func (c *Carbon) ToRssString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RssLayout)
}
// ToW3cString outputs a string in "2006-01-02T15:04:05Z07:00" layout.
// 输出 "2006-01-02T15:04:05Z07:00" 格式字符串
func (c *Carbon) ToW3cString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(W3cLayout)
}
// ToUnixDateString outputs a string in "Mon Jan _2 15:04:05 MST 2006" layout.
// 输出 "Mon Jan _2 15:04:05 MST 2006" 格式字符串
func (c *Carbon) ToUnixDateString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(UnixDateLayout)
}
// ToRubyDateString outputs a string in "Mon Jan 02 15:04:05 -0700 2006" layout.
// 输出 "Mon Jan 02 15:04:05 -0700 2006" 格式字符串
func (c *Carbon) ToRubyDateString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RubyDateLayout)
}
// ToKitchenString outputs a string in "3:04PM" layout.
// 输出 "3:04PM" 格式字符串
func (c *Carbon) ToKitchenString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(KitchenLayout)
}
// ToIso8601String outputs a string in "2006-01-02T15:04:05-07:00" layout.
// 输出 "2006-01-02T15:04:05-07:00" 格式字符串
func (c *Carbon) ToIso8601String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601Layout)
}
// ToIso8601MilliString outputs a string in "2006-01-02T15:04:05.999-07:00" layout.
// 输出 "2006-01-02T15:04:05.999-07:00" 格式字符串
func (c *Carbon) ToIso8601MilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601MilliLayout)
}
// ToIso8601MicroString outputs a string in "2006-01-02T15:04:05.999999-07:00" layout.
// 输出 "2006-01-02T15:04:05.999999-07:00" 格式字符串
func (c *Carbon) ToIso8601MicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601MicroLayout)
}
// ToIso8601NanoString outputs a string in "2006-01-02T15:04:05.999999999-07:00" layout.
// 输出 "2006-01-02T15:04:05.999999999-07:00" 格式字符串
func (c *Carbon) ToIso8601NanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601NanoLayout)
}
// ToIso8601ZuluString outputs a string in "2006-01-02T15:04:05Z" layout.
// 输出 "2006-01-02T15:04:05Z" 格式字符串
func (c *Carbon) ToIso8601ZuluString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601ZuluLayout)
}
// ToIso8601ZuluMilliString outputs a string in "2006-01-02T15:04:05.999Z" layout.
// 输出 "2006-01-02T15:04:05.999Z" 格式字符串
func (c *Carbon) ToIso8601ZuluMilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601ZuluMilliLayout)
}
// ToIso8601ZuluMicroString outputs a string in "2006-01-02T15:04:05.999999Z" layout.
// 输出 "2006-01-02T15:04:05.999999Z" 格式字符串
func (c *Carbon) ToIso8601ZuluMicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601ZuluMicroLayout)
}
// ToIso8601ZuluNanoString outputs a string in "2006-01-02T15:04:05.999999999Z" layout.
// 输出 "2006-01-02T15:04:05.999999999Z" 格式字符串
func (c *Carbon) ToIso8601ZuluNanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(ISO8601ZuluNanoLayout)
}
// ToRfc822String outputs a string in "02 Jan 06 15:04 MST" layout.
// 输出 "02 Jan 06 15:04 MST" 格式字符串
func (c *Carbon) ToRfc822String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC822Layout)
}
// ToRfc822zString outputs a string in "02 Jan 06 15:04 -0700" layout.
// 输出 "02 Jan 06 15:04 -0700" 格式字符串
func (c *Carbon) ToRfc822zString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC822ZLayout)
}
// ToRfc850String outputs a string in "Monday, 02-Jan-06 15:04:05 MST" layout.
// 输出 "Monday, 02-Jan-06 15:04:05 MST" 格式字符串
func (c *Carbon) ToRfc850String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC850Layout)
}
// ToRfc1036String outputs a string in "Mon, 02 Jan 06 15:04:05 -0700" layout.
// 输出 "Mon, 02 Jan 06 15:04:05 -0700" 格式字符串
func (c *Carbon) ToRfc1036String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC1036Layout)
}
// ToRfc1123String outputs a string in "Mon, 02 Jan 2006 15:04:05 MST" layout.
// 输出 "Mon, 02 Jan 2006 15:04:05 MST" 格式字符串
func (c *Carbon) ToRfc1123String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC1123Layout)
}
// ToRfc1123zString outputs a string in "Mon, 02 Jan 2006 15:04:05 -0700" layout.
// 输出 "Mon, 02 Jan 2006 15:04:05 -0700" 格式字符串
func (c *Carbon) ToRfc1123zString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC1123ZLayout)
}
// ToRfc2822String outputs a string in "Mon, 02 Jan 2006 15:04:05 -0700" layout.
// 输出 "Mon, 02 Jan 2006 15:04:05 -0700" 格式字符串
func (c *Carbon) ToRfc2822String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC2822Layout)
}
// ToRfc3339String outputs a string in "2006-01-02T15:04:05Z07:00" layout.
// 输出 "2006-01-02T15:04:05Z07:00" 格式字符串
func (c *Carbon) ToRfc3339String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC3339Layout)
}
// ToRfc3339MilliString outputs a string in "2006-01-02T15:04:05.999Z07:00" layout.
// 输出 "2006-01-02T15:04:05.999Z07:00" 格式字符串
func (c *Carbon) ToRfc3339MilliString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC3339MilliLayout)
}
// ToRfc3339MicroString outputs a string in "2006-01-02T15:04:05.999999Z07:00" layout.
// 输出 "2006-01-02T15:04:05.999999Z07:00" 格式字符串
func (c *Carbon) ToRfc3339MicroString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC3339MicroLayout)
}
// ToRfc3339NanoString outputs a string in "2006-01-02T15:04:05.999999999Z07:00" layout.
// 输出 "2006-01-02T15:04:05.999999999Z07:00" 格式字符串
func (c *Carbon) ToRfc3339NanoString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC3339NanoLayout)
}
// ToRfc7231String outputs a string in "Mon, 02 Jan 2006 15:04:05 GMT" layout.
// 输出 "Mon, 02 Jan 2006 15:04:05 GMT" 格式字符串
func (c *Carbon) ToRfc7231String(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(RFC7231Layout)
}
// ToFormattedDateString outputs a string in "Jan 2, 2006" layout.
// 输出 "Jan 2, 2006" 格式字符串
func (c *Carbon) ToFormattedDateString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(FormattedDateLayout)
}
// ToFormattedDayDateString outputs a string in "Mon, Jan 2, 2006" layout.
// 输出 "Jan 2, 2006" 格式字符串
func (c *Carbon) ToFormattedDayDateString(timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(FormattedDayDateLayout)
}
// Layout outputs a string by layout.
// 输出指定布局模板的时间字符串
func (c *Carbon) Layout(layout string, timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
return c.StdTime().Format(layout)
}
// Format outputs a string by format.
// 输出指定格式模板的时间字符串
func (c *Carbon) Format(format string, timezone ...string) string {
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.IsInvalid() {
return ""
}
buffer := bytes.NewBuffer(nil)
for i := 0; i < len(format); i++ {
if layout, ok := formatMap[format[i]]; ok {
// support for i18n specific symbols
switch format[i] {
case 'l': // week, such as Monday
buffer.WriteString(c.ToWeekString())
case 'D': // short week, such as Mon
buffer.WriteString(c.ToShortWeekString())
case 'F': // month, such as January
buffer.WriteString(c.ToMonthString())
case 'M': // short month, such as Jan
buffer.WriteString(c.ToShortMonthString())
case 'U': // timestamp with second, such as 1596604455
buffer.WriteString(strconv.FormatInt(c.Timestamp(), 10))
case 'V': // timestamp with millisecond, such as 1596604455000
buffer.WriteString(strconv.FormatInt(c.TimestampMilli(), 10))
case 'X': // timestamp with microsecond, such as 1596604455000000
buffer.WriteString(strconv.FormatInt(c.TimestampMicro(), 10))
case 'Z': // timestamp with nanoseconds, such as 1596604455000000000
buffer.WriteString(strconv.FormatInt(c.TimestampNano(), 10))
default: // common symbols
buffer.WriteString(c.StdTime().Format(layout))
}
} else {
switch format[i] {
case '\\': // raw output, no parse
buffer.WriteByte(format[i+1])
i++
continue
case 'W': // week number of the year in ISO-8601 format, ranging from 01-52
week := fmt.Sprintf("%02d", c.WeekOfYear())
buffer.WriteString(week)
case 'N': // day of the week as a number in ISO-8601 format, ranging from 01-7
week := fmt.Sprintf("%02d", c.DayOfWeek())
buffer.WriteString(week)
case 'S': // abbreviated suffix for the day of the month, such as st, nd, rd, th
suffix := "th"
switch c.Day() {
case 1, 21, 31:
suffix = "st"
case 2, 22:
suffix = "nd"
case 3, 23:
suffix = "rd"
}
buffer.WriteString(suffix)
case 'L': // whether it is a leap year, if it is a leap year, it is 1, otherwise it is 0
if c.IsLeapYear() {
buffer.WriteString("1")
} else {
buffer.WriteString("0")
}
case 'G': // 24-hour format, no padding, ranging from 0-23
buffer.WriteString(strconv.Itoa(c.Hour()))
case 'w': // day of the week represented by the number, ranging from 0-6
buffer.WriteString(strconv.Itoa(c.DayOfWeek() - 1))
case 't': // number of days in the month, ranging from 28-31
buffer.WriteString(strconv.Itoa(c.DaysInMonth()))
case 'e': // current location, such as UTC,GMT,Atlantic/Azores
buffer.WriteString(c.Timezone())
case 'q': // current quarter, ranging from 1-4
buffer.WriteString(strconv.Itoa(c.Quarter()))
case 'c': // current century, ranging from 0-99
buffer.WriteString(strconv.Itoa(c.Century()))
default:
buffer.WriteByte(format[i])
}
}
}
return buffer.String()
}

165
vendor/github.com/dromara/carbon/v2/parser.go generated vendored Normal file
View File

@@ -0,0 +1,165 @@
package carbon
import (
"strconv"
"time"
)
// Parse parses a standard time string as a Carbon instance.
// 将标准格式时间字符串解析成 Carbon 实例
func Parse(value string, timezone ...string) *Carbon {
c := NewCarbon()
if value == "" {
return nil
}
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
switch value {
case "now":
return Now(c.Timezone())
case "yesterday":
return Yesterday(c.Timezone())
case "tomorrow":
return Tomorrow(c.Timezone())
}
for _, layout := range supportedLayouts {
if tt, err := time.ParseInLocation(layout, value, c.loc); err == nil {
c.time = tt
c.layout = layout
return c
}
}
c.Error = failedParseError(value)
return c
}
// ParseByFormat parses a time string as a Carbon instance by format.
// 通过格式模板将时间字符串解析成 Carbon 实例
func ParseByFormat(value, format string, timezone ...string) *Carbon {
c := NewCarbon()
if value == "" {
return nil
}
if format == "" {
c.Error = emptyFormatError()
return c
}
c = ParseByLayout(value, format2layout(format), timezone...)
if c.HasError() {
c.Error = invalidFormatError(value, format)
}
return c
}
// ParseByLayout parses a time string as a Carbon instance by layout.
// 通过布局模板将时间字符串解析成 Carbon 实例
func ParseByLayout(value, layout string, timezone ...string) *Carbon {
c := NewCarbon()
if value == "" {
return nil
}
if layout == "" {
c.Error = emptyLayoutError()
return c
}
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
if layout == "timestamp" {
ts, err := strconv.ParseInt(value, 10, 64)
if err != nil {
c.Error = invalidTimestampError(value)
return c
}
return CreateFromTimestamp(ts, c.Timezone())
}
if layout == "timestampMilli" {
ts, err := strconv.ParseInt(value, 10, 64)
if err != nil {
c.Error = invalidTimestampError(value)
return c
}
return CreateFromTimestampMilli(ts, c.Timezone())
}
if layout == "timestampMicro" {
ts, err := strconv.ParseInt(value, 10, 64)
if err != nil {
c.Error = invalidTimestampError(value)
return c
}
return CreateFromTimestampMicro(ts, c.Timezone())
}
if layout == "timestampNano" {
ts, err := strconv.ParseInt(value, 10, 64)
if err != nil {
c.Error = invalidTimestampError(value)
return c
}
return CreateFromTimestampNano(ts, c.Timezone())
}
tt, err := time.ParseInLocation(layout, value, c.loc)
if err != nil {
c.Error = invalidLayoutError(value, layout)
return c
}
c.time = tt
c.layout = layout
return c
}
// ParseWithLayouts parses time string with layouts as a Carbon instance.
// 通过自定义布局模板将时间字符串解析成 Carbon 实例
func ParseWithLayouts(value string, layouts []string, timezone ...string) *Carbon {
c := NewCarbon()
if value == "" {
return nil
}
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
if len(layouts) == 0 {
return Parse(value, timezone...)
}
for _, layout := range append(supportedLayouts, layouts...) {
if tt, err := time.ParseInLocation(layout, value, c.loc); err == nil {
c.time = tt
c.layout = layout
return c
}
}
c.Error = failedParseError(value)
return c
}
// ParseWithFormats parses time string with formats as a Carbon instance.
// 通过自定义格式化模板将时间字符串解析成 Carbon 实例
func ParseWithFormats(value string, formats []string, timezone ...string) *Carbon {
c := NewCarbon()
if value == "" {
return nil
}
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
if len(formats) == 0 {
return Parse(value, timezone...)
}
var layouts []string
for _, format := range formats {
layouts = append(layouts, format2layout(format))
}
return ParseWithLayouts(value, layouts, timezone...)
}

131
vendor/github.com/dromara/carbon/v2/season.go generated vendored Normal file
View File

@@ -0,0 +1,131 @@
package carbon
import (
"strings"
)
var seasons = []struct {
month, index int
}{
{3, 0}, // spring
{4, 0}, // spring
{5, 0}, // spring
{6, 1}, // summer
{7, 1}, // summer
{8, 1}, // summer
{9, 2}, // autumn
{10, 2}, // autumn
{11, 2}, // autumn
{12, 3}, // winter
{1, 3}, // winter
{2, 3}, // winter
}
// Season gets season name according to the meteorological division method like "Spring", i18n is supported.
// 获取当前季节(以气象划分),支持 i18n
func (c *Carbon) Season() string {
if c.IsInvalid() {
return ""
}
if len(c.lang.resources) == 0 {
c.lang.SetLocale(DefaultLocale)
}
index := -1
month := c.Month()
for i := 0; i < len(seasons); i++ {
season := seasons[i]
if month == season.month {
index = season.index
}
}
c.lang.rw.RLock()
defer c.lang.rw.RUnlock()
if resources, ok := c.lang.resources["seasons"]; ok {
slice := strings.Split(resources, "|")
if len(slice) == QuartersPerYear {
return slice[index]
}
}
return ""
}
// StartOfSeason returns a Carbon instance for start of the season.
// 本季节开始时间
func (c *Carbon) StartOfSeason() *Carbon {
if c.IsInvalid() {
return c
}
year, month, _ := c.Date()
if month == 1 || month == 2 {
return create(year-1, 12, 1, 0, 0, 0, 0, c.Timezone())
}
return create(year, month/3*3, 1, 0, 0, 0, 0, c.Timezone())
}
// EndOfSeason returns a Carbon instance for end of the season.
// 本季节结束时间
func (c *Carbon) EndOfSeason() *Carbon {
if c.IsInvalid() {
return c
}
year, month, _ := c.Date()
if month == 1 || month == 2 {
return create(year, 3, 0, 23, 59, 59, 999999999, c.Timezone())
}
if month == 12 {
return create(year+1, 3, 0, 23, 59, 59, 999999999, c.Timezone())
}
return create(year, month/3*3+3, 0, 23, 59, 59, 999999999, c.Timezone())
}
// IsSpring reports whether is spring.
// 是否是春季
func (c *Carbon) IsSpring() bool {
if c.IsInvalid() {
return false
}
month := c.Month()
if month == 3 || month == 4 || month == 5 {
return true
}
return false
}
// IsSummer reports whether is summer.
// 是否是夏季
func (c *Carbon) IsSummer() bool {
if c.IsInvalid() {
return false
}
month := c.Month()
if month == 6 || month == 7 || month == 8 {
return true
}
return false
}
// IsAutumn reports whether is autumn.
// 是否是秋季
func (c *Carbon) IsAutumn() bool {
if c.IsInvalid() {
return false
}
month := c.Month()
if month == 9 || month == 10 || month == 11 {
return true
}
return false
}
// IsWinter reports whether is winter.
// 是否是冬季
func (c *Carbon) IsWinter() bool {
if c.IsInvalid() {
return false
}
month := c.Month()
if month == 12 || month == 1 || month == 2 {
return true
}
return false
}

398
vendor/github.com/dromara/carbon/v2/setter.go generated vendored Normal file
View File

@@ -0,0 +1,398 @@
package carbon
import (
"time"
)
// SetLayout sets layout.
// 设置布局模板
func (c *Carbon) SetLayout(layout string) *Carbon {
if layout == "" {
c.Error = emptyLayoutError()
}
if c.IsInvalid() {
return c
}
c.layout = layout
return c
}
// SetLayout sets globally default layout.
// 设置全局默认布局模板
func SetLayout(layout string) *Carbon {
c := NewCarbon().SetLayout(layout)
if !c.HasError() {
DefaultLayout = layout
}
return c
}
// SetFormat sets format.
// 设置格式模板
func (c *Carbon) SetFormat(format string) *Carbon {
if format == "" {
c.Error = emptyFormatError()
}
if c.IsInvalid() {
return c
}
c.layout = format2layout(format)
return c
}
// SetFormat sets globally default format.
// 设置全局默认格式模板
func SetFormat(format string) *Carbon {
layout := format2layout(format)
c := NewCarbon().SetLayout(layout)
if !c.HasError() {
DefaultLayout = layout
}
return c
}
// SetWeekStartsAt sets start day of the week.
// 设置周起始日期
func (c *Carbon) SetWeekStartsAt(day string) *Carbon {
if day == "" {
c.Error = emptyWeekStartsDayError()
}
if c.IsInvalid() {
return c
}
if weekday, ok := weekdays[day]; ok {
c.weekStartsAt = weekday
} else {
c.Error = invalidWeekStartsAtError(day)
}
return c
}
// SetWeekStartsAt sets globally default start day of the week.
// 设置全局默认周起始日期
func SetWeekStartsAt(day string) *Carbon {
c := NewCarbon().SetWeekStartsAt(day)
if !c.HasError() {
DefaultWeekStartsAt = day
}
return c
}
// SetTimezone sets timezone.
// 设置时区
func (c *Carbon) SetTimezone(name string) *Carbon {
if name == "" {
c.Error = emptyTimezoneError()
}
if c.IsInvalid() {
return c
}
c.loc, c.Error = getLocationByTimezone(name)
return c
}
// SetTimezone sets globally default timezone.
// 设置全局默认时区
func SetTimezone(name string) *Carbon {
c := NewCarbon().SetTimezone(name)
if !c.HasError() {
time.Local = c.loc
DefaultTimezone = name
}
return c
}
// SetLocation sets location.
// 设置位置
func (c *Carbon) SetLocation(loc *time.Location) *Carbon {
if loc == nil {
c.Error = nilLocationError()
}
if c.IsInvalid() {
return c
}
c.loc = loc
return c
}
// SetLocation sets globally default location.
// 设置全局默认位置
func SetLocation(loc *time.Location) *Carbon {
c := NewCarbon().SetLocation(loc)
if !c.HasError() {
time.Local = loc
DefaultTimezone = loc.String()
}
return c
}
// SetLocale sets locale.
// 设置语言区域
func (c *Carbon) SetLocale(locale string) *Carbon {
if locale == "" {
c.Error = emptyLocaleError()
}
if c.IsInvalid() {
return c
}
c.lang.SetLocale(locale)
c.Error = c.lang.Error
return c
}
// SetLocale sets globally default locale.
// 设置全局默认语言区域
func SetLocale(locale string) *Carbon {
c := NewCarbon().SetLocale(locale)
if !c.HasError() {
DefaultLocale = locale
}
return c
}
// SetLanguage sets language.
// 设置语言对象
func SetLanguage(lang *Language) *Carbon {
return NewCarbon().SetLanguage(lang)
}
// SetLanguage sets language.
// 设置语言对象
func (c *Carbon) SetLanguage(lang *Language) *Carbon {
if c.IsInvalid() {
return c
}
if lang == nil {
c.Error = nilLanguageError()
return c
}
c.lang.dir = lang.dir
c.lang.locale = lang.locale
c.lang.resources = lang.resources
c.lang.Error = lang.Error
return c
}
// SetDateTime sets year, month, day, hour, minute and second.
// 设置年、月、日、时、分、秒
func (c *Carbon) SetDateTime(year, month, day, hour, minute, second int) *Carbon {
if c.IsInvalid() {
return c
}
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetDateTimeMilli sets year, month, day, hour, minute, second and millisecond.
// 设置年、月、日、时、分、秒、毫秒
func (c *Carbon) SetDateTimeMilli(year, month, day, hour, minute, second, millisecond int) *Carbon {
if c.IsInvalid() {
return c
}
return create(year, month, day, hour, minute, second, millisecond*1e6, c.Timezone())
}
// SetDateTimeMicro sets year, month, day, hour, minute, second and microsecond.
// 设置年、月、日、时、分、秒、微秒
func (c *Carbon) SetDateTimeMicro(year, month, day, hour, minute, second, microsecond int) *Carbon {
if c.IsInvalid() {
return c
}
return create(year, month, day, hour, minute, second, microsecond*1e3, c.Timezone())
}
// SetDateTimeNano sets year, month, day, hour, minute, second and nanosecond.
// 设置年、月、日、时、分、秒、纳秒
func (c *Carbon) SetDateTimeNano(year, month, day, hour, minute, second, nanosecond int) *Carbon {
if c.IsInvalid() {
return c
}
return create(year, month, day, hour, minute, second, nanosecond, c.Timezone())
}
// SetDate sets year, month and day.
// 设置年、月、日
func (c *Carbon) SetDate(year, month, day int) *Carbon {
if c.IsInvalid() {
return c
}
hour, minute, second := c.Time()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetDateMilli sets year, month, day and millisecond.
// 设置年、月、日、毫秒
func (c *Carbon) SetDateMilli(year, month, day, millisecond int) *Carbon {
if c.IsInvalid() {
return c
}
hour, minute, second := c.Time()
return create(year, month, day, hour, minute, second, millisecond*1e6, c.Timezone())
}
// SetDateMicro sets year, month, day and microsecond.
// 设置年、月、日、微秒
func (c *Carbon) SetDateMicro(year, month, day, microsecond int) *Carbon {
if c.IsInvalid() {
return c
}
hour, minute, second := c.Time()
return create(year, month, day, hour, minute, second, microsecond*1e3, c.Timezone())
}
// SetDateNano sets year, month, day and nanosecond.
// 设置年、月、日、纳秒
func (c *Carbon) SetDateNano(year, month, day, nanosecond int) *Carbon {
if c.IsInvalid() {
return c
}
hour, minute, second := c.Time()
return create(year, month, day, hour, minute, second, nanosecond, c.Timezone())
}
// SetTime sets hour, minute and second.
// 设置时、分、秒
func (c *Carbon) SetTime(hour, minute, second int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetTimeMilli sets hour, minute, second and millisecond.
// 设置时、分、秒、毫秒
func (c *Carbon) SetTimeMilli(hour, minute, second, millisecond int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, hour, minute, second, millisecond*1e6, c.Timezone())
}
// SetTimeMicro sets hour, minute, second and microsecond.
// 设置时、分、秒、微秒
func (c *Carbon) SetTimeMicro(hour, minute, second, microsecond int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, hour, minute, second, microsecond*1e3, c.Timezone())
}
// SetTimeNano sets hour, minute, second and nanosecond.
// 设置、时、分、秒、纳秒
func (c *Carbon) SetTimeNano(hour, minute, second, nanosecond int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day := c.Date()
return create(year, month, day, hour, minute, second, nanosecond, c.Timezone())
}
// SetYear sets year.
// 设置年份
func (c *Carbon) SetYear(year int) *Carbon {
if c.IsInvalid() {
return c
}
_, month, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetYearNoOverflow sets year without overflowing month.
// 设置年份(月份不溢出)
func (c *Carbon) SetYearNoOverflow(year int) *Carbon {
if c.IsInvalid() {
return c
}
return c.AddYearsNoOverflow(year - c.Year())
}
// SetMonth sets month.
// 设置月份
func (c *Carbon) SetMonth(month int) *Carbon {
if c.IsInvalid() {
return c
}
year, _, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetMonthNoOverflow sets month without overflowing month.
// 设置月份(月份不溢出)
func (c *Carbon) SetMonthNoOverflow(month int) *Carbon {
if c.IsInvalid() {
return c
}
return c.AddMonthsNoOverflow(month - c.Month())
}
// SetDay sets day.
// 设置日期
func (c *Carbon) SetDay(day int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, _, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetHour sets hour.
// 设置小时
func (c *Carbon) SetHour(hour int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, _, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetMinute sets minute.
// 设置分钟
func (c *Carbon) SetMinute(minute int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, _, second := c.DateTime()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetSecond sets second.
// 设置秒数
func (c *Carbon) SetSecond(second int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, _ := c.DateTime()
return create(year, month, day, hour, minute, second, c.Nanosecond(), c.Timezone())
}
// SetMillisecond sets millisecond.
// 设置毫秒
func (c *Carbon) SetMillisecond(millisecond int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, millisecond*1e6, c.Timezone())
}
// SetMicrosecond sets microsecond.
// 设置微秒
func (c *Carbon) SetMicrosecond(microsecond int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, microsecond*1e3, c.Timezone())
}
// SetNanosecond sets nanosecond.
// 设置纳秒
func (c *Carbon) SetNanosecond(nanosecond int) *Carbon {
if c.IsInvalid() {
return c
}
year, month, day, hour, minute, second := c.DateTime()
return create(year, month, day, hour, minute, second, nanosecond, c.Timezone())
}

566
vendor/github.com/dromara/carbon/v2/traveler.go generated vendored Normal file
View File

@@ -0,0 +1,566 @@
package carbon
import (
"time"
)
// Now returns a Carbon instance for now.
// 当前
func Now(timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
if IsTestNow() {
return testNow.frozenNow
}
c.time = time.Now().In(c.loc)
return c
}
// Tomorrow returns a Carbon instance for tomorrow.
// 明天
func Tomorrow(timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
return Now(c.Timezone()).Copy().AddDay()
}
// Yesterday returns a Carbon instance for yesterday.
// 昨天
func Yesterday(timezone ...string) *Carbon {
c := NewCarbon()
if len(timezone) > 0 {
c.loc, c.Error = getLocationByTimezone(timezone[0])
}
if c.HasError() {
return c
}
return Now(c.Timezone()).Copy().SubDay()
}
// AddDuration adds one duration.
// 按照时长增加时间,支持整数/浮点数和符号ns(纳秒)、us(微妙)、ms(毫秒)、s(秒)、m(分钟)、h(小时)的组合
func (c *Carbon) AddDuration(duration string) *Carbon {
if c.IsInvalid() {
return c
}
td, err := parseByDuration(duration)
if err != nil {
c.Error = err
return c
}
c.time = c.StdTime().Add(td)
return c
}
// SubDuration subtracts one duration.
// 按照时长减少时间,支持整数/浮点数和符号ns(纳秒)、us(微妙)、ms(毫秒)、s(秒)、m(分钟)、h(小时)的组合
func (c *Carbon) SubDuration(duration string) *Carbon {
return c.AddDuration("-" + duration)
}
// AddCenturies adds some centuries.
// N个世纪后
func (c *Carbon) AddCenturies(centuries int) *Carbon {
return c.AddYears(centuries * YearsPerCentury)
}
// AddCenturiesNoOverflow adds some centuries without overflowing month.
// N个世纪后(月份不溢出)
func (c *Carbon) AddCenturiesNoOverflow(centuries int) *Carbon {
return c.AddYearsNoOverflow(centuries * YearsPerCentury)
}
// AddCentury adds one century.
// 1个世纪后
func (c *Carbon) AddCentury() *Carbon {
return c.AddCenturies(1)
}
// AddCenturyNoOverflow adds one century without overflowing month.
// 1个世纪后(月份不溢出)
func (c *Carbon) AddCenturyNoOverflow() *Carbon {
return c.AddCenturiesNoOverflow(1)
}
// SubCenturies subtracts some centuries.
// N个世纪前
func (c *Carbon) SubCenturies(centuries int) *Carbon {
return c.SubYears(centuries * YearsPerCentury)
}
// SubCenturiesNoOverflow subtracts some centuries without overflowing month.
// N个世纪前(月份不溢出)
func (c *Carbon) SubCenturiesNoOverflow(centuries int) *Carbon {
return c.SubYearsNoOverflow(centuries * YearsPerCentury)
}
// SubCentury subtracts one century.
// 1个世纪前
func (c *Carbon) SubCentury() *Carbon {
return c.SubCenturies(1)
}
// SubCenturyNoOverflow subtracts one century without overflowing month.
// 1个世纪前(月份不溢出)
func (c *Carbon) SubCenturyNoOverflow() *Carbon {
return c.SubCenturiesNoOverflow(1)
}
// AddDecades adds some decades.
// N个年代后
func (c *Carbon) AddDecades(decades int) *Carbon {
return c.AddYears(decades * YearsPerDecade)
}
// AddDecadesNoOverflow adds some decades without overflowing month.
// N个年代后(月份不溢出)
func (c *Carbon) AddDecadesNoOverflow(decades int) *Carbon {
return c.AddYearsNoOverflow(decades * YearsPerDecade)
}
// AddDecade adds one decade.
// 1个年代后
func (c *Carbon) AddDecade() *Carbon {
return c.AddDecades(1)
}
// AddDecadeNoOverflow adds one decade without overflowing month.
// 1个年代后(月份不溢出)
func (c *Carbon) AddDecadeNoOverflow() *Carbon {
return c.AddDecadesNoOverflow(1)
}
// SubDecades subtracts some decades.
// N个年代后
func (c *Carbon) SubDecades(decades int) *Carbon {
return c.SubYears(decades * YearsPerDecade)
}
// SubDecadesNoOverflow subtracts some decades without overflowing month.
// N个年代后(月份不溢出)
func (c *Carbon) SubDecadesNoOverflow(decades int) *Carbon {
return c.SubYearsNoOverflow(decades * YearsPerDecade)
}
// SubDecade subtracts one decade.
// 1个年代后
func (c *Carbon) SubDecade() *Carbon {
return c.SubDecades(1)
}
// SubDecadeNoOverflow subtracts one decade without overflowing month.
// 1个年代后(月份不溢出)
func (c *Carbon) SubDecadeNoOverflow() *Carbon {
return c.SubDecadesNoOverflow(1)
}
// AddYears adds some years.
// N年后
func (c *Carbon) AddYears(years int) *Carbon {
if c.IsInvalid() {
return c
}
c.time = c.StdTime().AddDate(years, 0, 0)
return c
}
// AddYearsNoOverflow adds some years without overflowing month.
// N年后(月份不溢出)
func (c *Carbon) AddYearsNoOverflow(years int) *Carbon {
if c.IsInvalid() {
return c
}
nanosecond := c.Nanosecond()
year, month, day, hour, minute, second := c.DateTime()
// 获取N年后本月的最后一天
lastYear, lastMonth, lastDay := create(year+years, month+1, 0, hour, minute, second, nanosecond, c.Timezone()).Date()
if day > lastDay {
day = lastDay
}
return create(lastYear, lastMonth, day, hour, minute, second, nanosecond, c.Timezone())
}
// AddYear adds one year.
// 1年后
func (c *Carbon) AddYear() *Carbon {
return c.AddYears(1)
}
// AddYearNoOverflow adds one year without overflowing month.
// 1年后(月份不溢出)
func (c *Carbon) AddYearNoOverflow() *Carbon {
return c.AddYearsNoOverflow(1)
}
// SubYears subtracts some years.
// N年前
func (c *Carbon) SubYears(years int) *Carbon {
if c.IsInvalid() {
return c
}
return c.AddYears(-years)
}
// SubYearsNoOverflow subtracts some years without overflowing month.
// N年前(月份不溢出)
func (c *Carbon) SubYearsNoOverflow(years int) *Carbon {
return c.AddYearsNoOverflow(-years)
}
// SubYear subtracts one year.
// 1年前
func (c *Carbon) SubYear() *Carbon {
return c.SubYears(1)
}
// SubYearNoOverflow subtracts one year without overflowing month.
// 1年前(月份不溢出)
func (c *Carbon) SubYearNoOverflow() *Carbon {
return c.SubYearsNoOverflow(1)
}
// AddQuarters adds some quarters
// N个季度后
func (c *Carbon) AddQuarters(quarters int) *Carbon {
return c.AddMonths(quarters * MonthsPerQuarter)
}
// AddQuartersNoOverflow adds quarters without overflowing month.
// N个季度后(月份不溢出)
func (c *Carbon) AddQuartersNoOverflow(quarters int) *Carbon {
return c.AddMonthsNoOverflow(quarters * MonthsPerQuarter)
}
// AddQuarter adds one quarter
// 1个季度后
func (c *Carbon) AddQuarter() *Carbon {
return c.AddQuarters(1)
}
// AddQuarterNoOverflow adds one quarter without overflowing month.
// 1个季度后(月份不溢出)
func (c *Carbon) AddQuarterNoOverflow() *Carbon {
return c.AddQuartersNoOverflow(1)
}
// SubQuarters subtracts some quarters.
// N个季度前
func (c *Carbon) SubQuarters(quarters int) *Carbon {
return c.AddQuarters(-quarters)
}
// SubQuartersNoOverflow subtracts some quarters without overflowing month.
// N个季度前(月份不溢出)
func (c *Carbon) SubQuartersNoOverflow(quarters int) *Carbon {
return c.AddMonthsNoOverflow(-quarters * MonthsPerQuarter)
}
// SubQuarter subtracts one quarter.
// 1个季度前
func (c *Carbon) SubQuarter() *Carbon {
return c.SubQuarters(1)
}
// SubQuarterNoOverflow subtracts one quarter without overflowing month.
// 1个季度前(月份不溢出)
func (c *Carbon) SubQuarterNoOverflow() *Carbon {
return c.SubQuartersNoOverflow(1)
}
// AddMonths adds some months.
// N个月后
func (c *Carbon) AddMonths(months int) *Carbon {
if c.IsInvalid() {
return c
}
c.time = c.StdTime().AddDate(0, months, 0)
return c
}
// AddMonthsNoOverflow adds some months without overflowing month.
// N个月后(月份不溢出)
func (c *Carbon) AddMonthsNoOverflow(months int) *Carbon {
if c.IsInvalid() {
return c
}
nanosecond := c.Nanosecond()
year, month, day, hour, minute, second := c.DateTime()
// 获取N月后的最后一天
lastYear, lastMonth, lastDay := create(year, month+months+1, 0, hour, minute, second, nanosecond, c.Timezone()).Date()
if day > lastDay {
day = lastDay
}
return create(lastYear, lastMonth, day, hour, minute, second, nanosecond, c.Timezone())
}
// AddMonth adds one month.
// 1个月后
func (c *Carbon) AddMonth() *Carbon {
return c.AddMonths(1)
}
// AddMonthNoOverflow adds one month without overflowing month.
// 1个月后(月份不溢出)
func (c *Carbon) AddMonthNoOverflow() *Carbon {
return c.AddMonthsNoOverflow(1)
}
// SubMonths subtracts some months.
// N个月前
func (c *Carbon) SubMonths(months int) *Carbon {
return c.AddMonths(-months)
}
// SubMonthsNoOverflow subtracts some months without overflowing month.
// N个月前(月份不溢出)
func (c *Carbon) SubMonthsNoOverflow(months int) *Carbon {
return c.AddMonthsNoOverflow(-months)
}
// SubMonth subtracts one month.
// 1个月前
func (c *Carbon) SubMonth() *Carbon {
return c.SubMonths(1)
}
// SubMonthNoOverflow subtracts one month without overflowing month.
// 1个月前(月份不溢出)
func (c *Carbon) SubMonthNoOverflow() *Carbon {
return c.SubMonthsNoOverflow(1)
}
// AddWeeks adds some weeks.
// N周后
func (c *Carbon) AddWeeks(weeks int) *Carbon {
return c.AddDays(weeks * DaysPerWeek)
}
// AddWeek adds one week.
// 1周后
func (c *Carbon) AddWeek() *Carbon {
return c.AddWeeks(1)
}
// SubWeeks subtracts some weeks.
// N周前
func (c *Carbon) SubWeeks(weeks int) *Carbon {
return c.SubDays(weeks * DaysPerWeek)
}
// SubWeek subtracts one week.
// 1周前
func (c *Carbon) SubWeek() *Carbon {
return c.SubWeeks(1)
}
// AddDays adds some days.
// N天后
func (c *Carbon) AddDays(days int) *Carbon {
if c.IsInvalid() {
return c
}
c.time = c.StdTime().AddDate(0, 0, days)
return c
}
// AddDay adds one day.
// 1天后
func (c *Carbon) AddDay() *Carbon {
return c.AddDays(1)
}
// SubDays subtracts some days.
// N天前
func (c *Carbon) SubDays(days int) *Carbon {
return c.AddDays(-days)
}
// SubDay subtracts one day.
// 1天前
func (c *Carbon) SubDay() *Carbon {
return c.SubDays(1)
}
// AddHours adds some hours.
// N小时后
func (c *Carbon) AddHours(hours int) *Carbon {
if c.IsInvalid() {
return c
}
td := time.Duration(hours) * time.Hour
c.time = c.StdTime().Add(td)
return c
}
// AddHour adds one hour.
// 1小时后
func (c *Carbon) AddHour() *Carbon {
return c.AddHours(1)
}
// SubHours subtracts some hours.
// N小时前
func (c *Carbon) SubHours(hours int) *Carbon {
return c.AddHours(-hours)
}
// SubHour subtracts one hour.
// 1小时前
func (c *Carbon) SubHour() *Carbon {
return c.SubHours(1)
}
// AddMinutes adds some minutes.
// N分钟后
func (c *Carbon) AddMinutes(minutes int) *Carbon {
if c.IsInvalid() {
return c
}
td := time.Duration(minutes) * time.Minute
c.time = c.StdTime().Add(td)
return c
}
// AddMinute adds one minute.
// 1分钟后
func (c *Carbon) AddMinute() *Carbon {
return c.AddMinutes(1)
}
// SubMinutes subtracts some minutes.
// N分钟前
func (c *Carbon) SubMinutes(minutes int) *Carbon {
return c.AddMinutes(-minutes)
}
// SubMinute subtracts one minute.
// 1分钟前
func (c *Carbon) SubMinute() *Carbon {
return c.SubMinutes(1)
}
// AddSeconds adds some seconds.
// N秒钟后
func (c *Carbon) AddSeconds(seconds int) *Carbon {
if c.IsInvalid() {
return c
}
td := time.Duration(seconds) * time.Second
c.time = c.StdTime().Add(td)
return c
}
// AddSecond adds one second.
// 1秒钟后
func (c *Carbon) AddSecond() *Carbon {
return c.AddSeconds(1)
}
// SubSeconds subtracts some seconds.
// N秒钟前
func (c *Carbon) SubSeconds(seconds int) *Carbon {
return c.AddSeconds(-seconds)
}
// SubSecond subtracts one second.
// 1秒钟前
func (c *Carbon) SubSecond() *Carbon {
return c.SubSeconds(1)
}
// AddMilliseconds adds some milliseconds.
// N毫秒后
func (c *Carbon) AddMilliseconds(milliseconds int) *Carbon {
if c.IsInvalid() {
return c
}
td := time.Duration(milliseconds) * time.Millisecond
c.time = c.StdTime().Add(td)
return c
}
// AddMillisecond adds one millisecond.
// 1毫秒后
func (c *Carbon) AddMillisecond() *Carbon {
return c.AddMilliseconds(1)
}
// SubMilliseconds subtracts some milliseconds.
// N毫秒前
func (c *Carbon) SubMilliseconds(milliseconds int) *Carbon {
return c.AddMilliseconds(-milliseconds)
}
// SubMillisecond subtracts one millisecond.
// 1毫秒前
func (c *Carbon) SubMillisecond() *Carbon {
return c.SubMilliseconds(1)
}
// AddMicroseconds adds some microseconds.
// N微秒后
func (c *Carbon) AddMicroseconds(microseconds int) *Carbon {
if c.IsInvalid() {
return c
}
td := time.Duration(microseconds) * time.Microsecond
c.time = c.StdTime().Add(td)
return c
}
// AddMicrosecond adds one microsecond.
// 1微秒后
func (c *Carbon) AddMicrosecond() *Carbon {
return c.AddMicroseconds(1)
}
// SubMicroseconds subtracts some microseconds.
// N微秒前
func (c *Carbon) SubMicroseconds(microseconds int) *Carbon {
return c.AddMicroseconds(-microseconds)
}
// SubMicrosecond subtracts one microsecond.
// 1微秒前
func (c *Carbon) SubMicrosecond() *Carbon {
return c.SubMicroseconds(1)
}
// AddNanoseconds adds some nanoseconds.
// N纳秒后
func (c *Carbon) AddNanoseconds(nanoseconds int) *Carbon {
if c.IsInvalid() {
return c
}
td := time.Duration(nanoseconds) * time.Nanosecond
c.time = c.StdTime().Add(td)
return c
}
// AddNanosecond adds one nanosecond.
// 1纳秒后
func (c *Carbon) AddNanosecond() *Carbon {
return c.AddNanoseconds(1)
}
// SubNanoseconds subtracts some nanoseconds.
// N纳秒前
func (c *Carbon) SubNanoseconds(nanoseconds int) *Carbon {
return c.AddNanoseconds(-nanoseconds)
}
// SubNanosecond subtracts one nanosecond.
// 1纳秒前
func (c *Carbon) SubNanosecond() *Carbon {
return c.SubNanoseconds(1)
}

89
vendor/github.com/dromara/carbon/v2/types.go generated vendored Normal file
View File

@@ -0,0 +1,89 @@
package carbon
// Timestamp defines a Timestamp type.
// 定义 Timestamp 字段类型
type Timestamp int64
// SetPrecision implements TimestampFactory interface for Timestamp type.
// 实现 TimestampFactory 接口
func (t Timestamp) SetPrecision() int64 {
return PrecisionSecond
}
// TimestampMilli defines a TimestampMilli type.
// 定义 TimestampMilli 字段类型
type TimestampMilli int64
// SetPrecision implements TimestampFactory interface for TimestampMilli type.
// 实现 TimestampFactory 接口
func (t TimestampMilli) SetPrecision() int64 {
return PrecisionMillisecond
}
// TimestampMicro defines a TimestampMicro type.
// 定义 TimestampMicro 字段类型
type TimestampMicro int64
// SetPrecision implements TimestampFactory interface for TimestampMicro type.
// 实现 TimestampFactory 接口
func (t TimestampMicro) SetPrecision() int64 {
return PrecisionMicrosecond
}
// TimestampNano defines a TimestampNano type.
// 定义 TimestampNano 字段类型
type TimestampNano int64
// SetPrecision implements TimestampFactory interface for TimestampNano type.
// 实现 TimestampFactory 接口
func (t TimestampNano) SetPrecision() int64 {
return PrecisionNanosecond
}
// DateTime defines a DateTime type.
// 定义 DateTime 字段类型
type DateTime string
// SetFormat implements FormatFactory interface for DateTime type.
// 实现 FormatFactory 接口
func (t DateTime) SetFormat() string {
return DateTimeFormat
}
// SetLayout implements LayoutFactory interface for DateTime type.
// 实现 LayoutFactory 接口
func (t DateTime) SetLayout() string {
return DateTimeLayout
}
// Date defines a Date type.
// 定义 Date 字段类型
type Date string
// SetFormat implements FormatFactory interface for Date type.
// 实现 FormatFactory 接口
func (t Date) SetFormat() string {
return DateFormat
}
// SetLayout implements LayoutFactory interface for Date type.
// 实现 LayoutFactory 接口
func (t Date) SetLayout() string {
return DateLayout
}
// Time defines a Time struct.
// 定义 Time 字段类型
type Time string
// SetFormat implements FormatFactory interface for Time type.
// 实现 FormatFactory 接口
func (t Time) SetFormat() string {
return TimeFormat
}
// SetLayout implements LayoutFactory interface for Time type.
// 实现 LayoutFactory 接口
func (t Time) SetLayout() string {
return TimeLayout
}

View File

@@ -1,3 +1,15 @@
# 5.7.2 (December 21, 2024)
* Fix prepared statement already exists on batch prepare failure
* Add commit query to tx options (Lucas Hild)
* Fix pgtype.Timestamp json unmarshal (Shean de Montigny-Desautels)
* Add message body size limits in frontend and backend (zene)
* Add xid8 type
* Ensure planning encodes and scans cannot infinitely recurse
* Implement pgtype.UUID.String() (Konstantin Grachev)
* Switch from ExecParams to Exec in ValidateConnectTargetSessionAttrs functions (Alexander Rumyantsev)
* Update golang.org/x/crypto
# 5.7.1 (September 10, 2024)
* Fix data race in tracelog.TraceLog

View File

@@ -84,7 +84,7 @@ It is also possible to use the `database/sql` interface and convert a connection
## Testing
See CONTRIBUTING.md for setup instructions.
See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions.
## Architecture
@@ -126,7 +126,7 @@ pgerrcode contains constants for the PostgreSQL error codes.
## Adapters for 3rd Party Tracers
* [https://github.com/jackhopner/pgx-xray-tracer](https://github.com/jackhopner/pgx-xray-tracer)
* [github.com/jackhopner/pgx-xray-tracer](https://github.com/jackhopner/pgx-xray-tracer)
## Adapters for 3rd Party Loggers
@@ -156,7 +156,7 @@ Library for scanning data from a database into Go structs and more.
A carefully designed SQL client for making using SQL easier,
more productive, and less error-prone on Golang.
### [https://github.com/otan/gopgkrb5](https://github.com/otan/gopgkrb5)
### [github.com/otan/gopgkrb5](https://github.com/otan/gopgkrb5)
Adds GSSAPI / Kerberos authentication support.
@@ -169,6 +169,6 @@ Explicit data mapping and scanning library for Go structs and slices.
Type safe and flexible package for scanning database data into Go types.
Supports, structs, maps, slices and custom mapping functions.
### [https://github.com/z0ne-dev/mgx](https://github.com/z0ne-dev/mgx)
### [github.com/z0ne-dev/mgx](https://github.com/z0ne-dev/mgx)
Code first migration library for native pgx (no database/sql abstraction).

View File

@@ -650,21 +650,32 @@ const (
// registered with pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are
// unregistered or ambiguous. e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know
// the PostgreSQL type can use a map[string]string directly as an argument. This mode cannot.
//
// On rare occasions user defined types may behave differently when encoded in the text format instead of the binary
// format. For example, this could happen if a "type RomanNumeral int32" implements fmt.Stringer to format integers as
// Roman numerals (e.g. 7 is VII). The binary format would properly encode the integer 7 as the binary value for 7.
// But the text format would encode the integer 7 as the string "VII". As QueryExecModeExec uses the text format, it
// is possible that changing query mode from another mode to QueryExecModeExec could change the behavior of the query.
// This should not occur with types pgx supports directly and can be avoided by registering the types with
// pgtype.Map.RegisterDefaultPgType and implementing the appropriate type interfaces. In the cas of RomanNumeral, it
// should implement pgtype.Int64Valuer.
QueryExecModeExec
// Use the simple protocol. Assume the PostgreSQL query parameter types based on the Go type of the arguments.
// Queries are executed in a single round trip. Type mappings can be registered with
// pgtype.Map.RegisterDefaultPgType. Queries will be rejected that have arguments that are unregistered or ambiguous.
// e.g. A map[string]string may have the PostgreSQL type json or hstore. Modes that know the PostgreSQL type can use
// a map[string]string directly as an argument. This mode cannot.
// Use the simple protocol. Assume the PostgreSQL query parameter types based on the Go type of the arguments. Queries
// are executed in a single round trip. Type mappings can be registered with pgtype.Map.RegisterDefaultPgType. Queries
// will be rejected that have arguments that are unregistered or ambiguous. e.g. A map[string]string may have the
// PostgreSQL type json or hstore. Modes that know the PostgreSQL type can use a map[string]string directly as an
// argument. This mode cannot.
//
// QueryExecModeSimpleProtocol should have the user application visible behavior as QueryExecModeExec with minor
// exceptions such as behavior when multiple result returning queries are erroneously sent in a single string.
// QueryExecModeSimpleProtocol should have the user application visible behavior as QueryExecModeExec. This includes
// the warning regarding differences in text format and binary format encoding with user defined types. There may be
// other minor exceptions such as behavior when multiple result returning queries are erroneously sent in a single
// string.
//
// QueryExecModeSimpleProtocol uses client side parameter interpolation. All values are quoted and escaped. Prefer
// QueryExecModeExec over QueryExecModeSimpleProtocol whenever possible. In general QueryExecModeSimpleProtocol
// should only be used if connecting to a proxy server, connection pool server, or non-PostgreSQL server that does
// not support the extended protocol.
// QueryExecModeExec over QueryExecModeSimpleProtocol whenever possible. In general QueryExecModeSimpleProtocol should
// only be used if connecting to a proxy server, connection pool server, or non-PostgreSQL server that does not
// support the extended protocol.
QueryExecModeSimpleProtocol
)
@@ -904,6 +915,9 @@ func (c *Conn) QueryRow(ctx context.Context, sql string, args ...any) Row {
// SendBatch sends all queued queries to the server at once. All queries are run in an implicit transaction unless
// explicit transaction control statements are executed. The returned BatchResults must be closed before the connection
// is used again.
//
// Depending on the QueryExecMode, all queries may be prepared before any are executed. This means that creating a table
// and using it in a subsequent query in the same batch can fail.
func (c *Conn) SendBatch(ctx context.Context, b *Batch) (br BatchResults) {
if c.batchTracer != nil {
ctx = c.batchTracer.TraceBatchStart(ctx, c, TraceBatchStartData{Batch: b})
@@ -1126,47 +1140,64 @@ func (c *Conn) sendBatchExtendedWithDescription(ctx context.Context, b *Batch, d
// Prepare any needed queries
if len(distinctNewQueries) > 0 {
for _, sd := range distinctNewQueries {
pipeline.SendPrepare(sd.Name, sd.SQL, nil)
}
err := func() (err error) {
for _, sd := range distinctNewQueries {
pipeline.SendPrepare(sd.Name, sd.SQL, nil)
}
err := pipeline.Sync()
if err != nil {
return &pipelineBatchResults{ctx: ctx, conn: c, err: err, closed: true}
}
// Store all statements we are preparing into the cache. It's fine if it overflows because HandleInvalidated will
// clean them up later.
if sdCache != nil {
for _, sd := range distinctNewQueries {
sdCache.Put(sd)
}
}
// If something goes wrong preparing the statements, we need to invalidate the cache entries we just added.
defer func() {
if err != nil && sdCache != nil {
for _, sd := range distinctNewQueries {
sdCache.Invalidate(sd.SQL)
}
}
}()
err = pipeline.Sync()
if err != nil {
return err
}
for _, sd := range distinctNewQueries {
results, err := pipeline.GetResults()
if err != nil {
return err
}
resultSD, ok := results.(*pgconn.StatementDescription)
if !ok {
return fmt.Errorf("expected statement description, got %T", results)
}
// Fill in the previously empty / pending statement descriptions.
sd.ParamOIDs = resultSD.ParamOIDs
sd.Fields = resultSD.Fields
}
for _, sd := range distinctNewQueries {
results, err := pipeline.GetResults()
if err != nil {
return &pipelineBatchResults{ctx: ctx, conn: c, err: err, closed: true}
return err
}
resultSD, ok := results.(*pgconn.StatementDescription)
_, ok := results.(*pgconn.PipelineSync)
if !ok {
return &pipelineBatchResults{ctx: ctx, conn: c, err: fmt.Errorf("expected statement description, got %T", results), closed: true}
return fmt.Errorf("expected sync, got %T", results)
}
// Fill in the previously empty / pending statement descriptions.
sd.ParamOIDs = resultSD.ParamOIDs
sd.Fields = resultSD.Fields
}
results, err := pipeline.GetResults()
return nil
}()
if err != nil {
return &pipelineBatchResults{ctx: ctx, conn: c, err: err, closed: true}
}
_, ok := results.(*pgconn.PipelineSync)
if !ok {
return &pipelineBatchResults{ctx: ctx, conn: c, err: fmt.Errorf("expected sync, got %T", results), closed: true}
}
}
// Put all statements into the cache. It's fine if it overflows because HandleInvalidated will clean them up later.
if sdCache != nil {
for _, sd := range distinctNewQueries {
sdCache.Put(sd)
}
}
// Queue the queries.

View File

@@ -861,12 +861,12 @@ func makeConnectTimeoutDialFunc(timeout time.Duration) DialFunc {
// ValidateConnectTargetSessionAttrsReadWrite is a ValidateConnectFunc that implements libpq compatible
// target_session_attrs=read-write.
func ValidateConnectTargetSessionAttrsReadWrite(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "show transaction_read_only", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
result, err := pgConn.Exec(ctx, "show transaction_read_only").ReadAll()
if err != nil {
return err
}
if string(result.Rows[0][0]) == "on" {
if string(result[0].Rows[0][0]) == "on" {
return errors.New("read only connection")
}
@@ -876,12 +876,12 @@ func ValidateConnectTargetSessionAttrsReadWrite(ctx context.Context, pgConn *PgC
// ValidateConnectTargetSessionAttrsReadOnly is a ValidateConnectFunc that implements libpq compatible
// target_session_attrs=read-only.
func ValidateConnectTargetSessionAttrsReadOnly(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "show transaction_read_only", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
result, err := pgConn.Exec(ctx, "show transaction_read_only").ReadAll()
if err != nil {
return err
}
if string(result.Rows[0][0]) != "on" {
if string(result[0].Rows[0][0]) != "on" {
return errors.New("connection is not read only")
}
@@ -891,12 +891,12 @@ func ValidateConnectTargetSessionAttrsReadOnly(ctx context.Context, pgConn *PgCo
// ValidateConnectTargetSessionAttrsStandby is a ValidateConnectFunc that implements libpq compatible
// target_session_attrs=standby.
func ValidateConnectTargetSessionAttrsStandby(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
result, err := pgConn.Exec(ctx, "select pg_is_in_recovery()").ReadAll()
if err != nil {
return err
}
if string(result.Rows[0][0]) != "t" {
if string(result[0].Rows[0][0]) != "t" {
return errors.New("server is not in hot standby mode")
}
@@ -906,12 +906,12 @@ func ValidateConnectTargetSessionAttrsStandby(ctx context.Context, pgConn *PgCon
// ValidateConnectTargetSessionAttrsPrimary is a ValidateConnectFunc that implements libpq compatible
// target_session_attrs=primary.
func ValidateConnectTargetSessionAttrsPrimary(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
result, err := pgConn.Exec(ctx, "select pg_is_in_recovery()").ReadAll()
if err != nil {
return err
}
if string(result.Rows[0][0]) == "t" {
if string(result[0].Rows[0][0]) == "t" {
return errors.New("server is in standby mode")
}
@@ -921,12 +921,12 @@ func ValidateConnectTargetSessionAttrsPrimary(ctx context.Context, pgConn *PgCon
// ValidateConnectTargetSessionAttrsPreferStandby is a ValidateConnectFunc that implements libpq compatible
// target_session_attrs=prefer-standby.
func ValidateConnectTargetSessionAttrsPreferStandby(ctx context.Context, pgConn *PgConn) error {
result := pgConn.ExecParams(ctx, "select pg_is_in_recovery()", nil, nil, nil, nil).Read()
if result.Err != nil {
return result.Err
result, err := pgConn.Exec(ctx, "select pg_is_in_recovery()").ReadAll()
if err != nil {
return err
}
if string(result.Rows[0][0]) != "t" {
if string(result[0].Rows[0][0]) != "t" {
return &NotPreferredError{err: errors.New("server is not in hot standby mode")}
}

View File

@@ -175,7 +175,13 @@ func (b *Backend) Receive() (FrontendMessage, error) {
}
b.msgType = header[0]
b.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
msgLength := int(binary.BigEndian.Uint32(header[1:]))
if msgLength < 4 {
return nil, fmt.Errorf("invalid message length: %d", msgLength)
}
b.bodyLen = msgLength - 4
if b.maxBodyLen > 0 && b.bodyLen > b.maxBodyLen {
return nil, &ExceededMaxBodyLenErr{b.maxBodyLen, b.bodyLen}
}
@@ -282,9 +288,10 @@ func (b *Backend) SetAuthType(authType uint32) error {
return nil
}
// SetMaxBodyLen sets the maximum length of a message body in octets. If a message body exceeds this length, Receive will return
// an error. This is useful for protecting against malicious clients that send large messages with the intent of
// causing memory exhaustion.
// SetMaxBodyLen sets the maximum length of a message body in octets.
// If a message body exceeds this length, Receive will return an error.
// This is useful for protecting against malicious clients that send
// large messages with the intent of causing memory exhaustion.
// The default value is 0.
// If maxBodyLen is 0, then no maximum is enforced.
func (b *Backend) SetMaxBodyLen(maxBodyLen int) {

View File

@@ -54,6 +54,7 @@ type Frontend struct {
portalSuspended PortalSuspended
bodyLen int
maxBodyLen int // maxBodyLen is the maximum length of a message body in octets. If a message body exceeds this length, Receive will return an error.
msgType byte
partialMsg bool
authType uint32
@@ -317,6 +318,9 @@ func (f *Frontend) Receive() (BackendMessage, error) {
}
f.bodyLen = msgLength - 4
if f.maxBodyLen > 0 && f.bodyLen > f.maxBodyLen {
return nil, &ExceededMaxBodyLenErr{f.maxBodyLen, f.bodyLen}
}
f.partialMsg = true
}
@@ -452,3 +456,13 @@ func (f *Frontend) GetAuthType() uint32 {
func (f *Frontend) ReadBufferLen() int {
return f.cr.wp - f.cr.rp
}
// SetMaxBodyLen sets the maximum length of a message body in octets.
// If a message body exceeds this length, Receive will return an error.
// This is useful for protecting against a corrupted server that sends
// messages with incorrect length, which can cause memory exhaustion.
// The default value is 0.
// If maxBodyLen is 0, then no maximum is enforced.
func (f *Frontend) SetMaxBodyLen(maxBodyLen int) {
f.maxBodyLen = maxBodyLen
}

View File

@@ -25,7 +25,7 @@ func BenchmarkQuery<%= format_name %>FormatDecode_PG_<%= pg_type %>_to_Go_<%= go
rows, _ := conn.Query(
ctx,
`select <% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>n::<%= pg_type %> + <%= col_idx%><% end %> from generate_series(1, <%= rows %>) n`,
[]any{pgx.QueryResultFormats{<%= format_code %>}},
pgx.QueryResultFormats{<%= format_code %>},
)
_, err := pgx.ForEachRow(rows, []any{<% columns.times do |col_idx| %><% if col_idx != 0 %>, <% end %>&v[<%= col_idx%>]<% end %>}, func() error { return nil })
if err != nil {
@@ -49,7 +49,7 @@ func BenchmarkQuery<%= format_name %>FormatDecode_PG_Int4Array_With_Go_Int4Array
rows, _ := conn.Query(
ctx,
`select array_agg(n) from generate_series(1, <%= array_size %>) n`,
[]any{pgx.QueryResultFormats{<%= format_code %>}},
pgx.QueryResultFormats{<%= format_code %>},
)
_, err := pgx.ForEachRow(rows, []any{&v}, func() error { return nil })
if err != nil {

View File

@@ -130,7 +130,7 @@ func (c *JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanP
// https://github.com/jackc/pgx/issues/1691 -- ** anything else
if wrapperPlan, nextDst, ok := TryPointerPointerScanPlan(target); ok {
if nextPlan := m.planScan(oid, format, nextDst); nextPlan != nil {
if nextPlan := m.planScan(oid, format, nextDst, 0); nextPlan != nil {
if _, failed := nextPlan.(*scanPlanFail); !failed {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
@@ -143,10 +143,12 @@ func (c *JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanP
case BytesScanner:
return scanPlanBinaryBytesToBytesScanner{}
}
// Cannot rely on sql.Scanner being handled later because scanPlanJSONToJSONUnmarshal will take precedence.
//
// https://github.com/jackc/pgx/issues/1418
case sql.Scanner:
if isSQLScanner(target) {
return &scanPlanSQLScanner{formatCode: format}
}
@@ -155,6 +157,20 @@ func (c *JSONCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanP
}
}
// we need to check if the target is a pointer to a sql.Scanner (or any of the pointer ref tree implements a sql.Scanner).
//
// https://github.com/jackc/pgx/issues/2146
func isSQLScanner(v any) bool {
val := reflect.ValueOf(v)
for val.Kind() == reflect.Ptr {
if _, ok := val.Interface().(sql.Scanner); ok {
return true
}
val = val.Elem()
}
return false
}
type scanPlanAnyToString struct{}
func (scanPlanAnyToString) Scan(src []byte, dst any) error {

View File

@@ -29,6 +29,7 @@ const (
XMLOID = 142
XMLArrayOID = 143
JSONArrayOID = 199
XID8ArrayOID = 271
PointOID = 600
LsegOID = 601
PathOID = 602
@@ -117,6 +118,7 @@ const (
TstzmultirangeOID = 4534
DatemultirangeOID = 4535
Int8multirangeOID = 4536
XID8OID = 5069
Int4multirangeArrayOID = 6150
NummultirangeArrayOID = 6151
TsmultirangeArrayOID = 6152
@@ -394,7 +396,12 @@ type scanPlanSQLScanner struct {
}
func (plan *scanPlanSQLScanner) Scan(src []byte, dst any) error {
scanner := dst.(sql.Scanner)
scanner := getSQLScanner(dst)
if scanner == nil {
return fmt.Errorf("cannot scan into %T", dst)
}
if src == nil {
// This is necessary because interface value []byte:nil does not equal nil:nil for the binary format path and the
// text format path would be converted to empty string.
@@ -406,6 +413,21 @@ func (plan *scanPlanSQLScanner) Scan(src []byte, dst any) error {
}
}
// we don't know if the target is a sql.Scanner or a pointer on a sql.Scanner, so we need to check recursively
func getSQLScanner(target any) sql.Scanner {
val := reflect.ValueOf(target)
for val.Kind() == reflect.Ptr {
if _, ok := val.Interface().(sql.Scanner); ok {
if val.IsNil() {
val.Set(reflect.New(val.Type().Elem()))
}
return val.Interface().(sql.Scanner)
}
val = val.Elem()
}
return nil
}
type scanPlanString struct{}
func (scanPlanString) Scan(src []byte, dst any) error {
@@ -449,14 +471,14 @@ func (plan *scanPlanFail) Scan(src []byte, dst any) error {
// As a horrible hack try all types to find anything that can scan into dst.
for oid := range plan.m.oidToType {
// using planScan instead of Scan or PlanScan to avoid polluting the planned scan cache.
plan := plan.m.planScan(oid, plan.formatCode, dst)
plan := plan.m.planScan(oid, plan.formatCode, dst, 0)
if _, ok := plan.(*scanPlanFail); !ok {
return plan.Scan(src, dst)
}
}
for oid := range defaultMap.oidToType {
if _, ok := plan.m.oidToType[oid]; !ok {
plan := plan.m.planScan(oid, plan.formatCode, dst)
plan := plan.m.planScan(oid, plan.formatCode, dst, 0)
if _, ok := plan.(*scanPlanFail); !ok {
return plan.Scan(src, dst)
}
@@ -1064,6 +1086,14 @@ func (plan *wrapPtrArrayReflectScanPlan) Scan(src []byte, target any) error {
// PlanScan prepares a plan to scan a value into target.
func (m *Map) PlanScan(oid uint32, formatCode int16, target any) ScanPlan {
return m.planScanDepth(oid, formatCode, target, 0)
}
func (m *Map) planScanDepth(oid uint32, formatCode int16, target any, depth int) ScanPlan {
if depth > 8 {
return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
}
oidMemo := m.memoizedScanPlans[oid]
if oidMemo == nil {
oidMemo = make(map[reflect.Type][2]ScanPlan)
@@ -1073,7 +1103,7 @@ func (m *Map) PlanScan(oid uint32, formatCode int16, target any) ScanPlan {
typeMemo := oidMemo[targetReflectType]
plan := typeMemo[formatCode]
if plan == nil {
plan = m.planScan(oid, formatCode, target)
plan = m.planScan(oid, formatCode, target, depth)
typeMemo[formatCode] = plan
oidMemo[targetReflectType] = typeMemo
}
@@ -1081,7 +1111,7 @@ func (m *Map) PlanScan(oid uint32, formatCode int16, target any) ScanPlan {
return plan
}
func (m *Map) planScan(oid uint32, formatCode int16, target any) ScanPlan {
func (m *Map) planScan(oid uint32, formatCode int16, target any, depth int) ScanPlan {
if target == nil {
return &scanPlanFail{m: m, oid: oid, formatCode: formatCode}
}
@@ -1141,7 +1171,7 @@ func (m *Map) planScan(oid uint32, formatCode int16, target any) ScanPlan {
for _, f := range m.TryWrapScanPlanFuncs {
if wrapperPlan, nextDst, ok := f(target); ok {
if nextPlan := m.planScan(oid, formatCode, nextDst); nextPlan != nil {
if nextPlan := m.planScanDepth(oid, formatCode, nextDst, depth+1); nextPlan != nil {
if _, failed := nextPlan.(*scanPlanFail); !failed {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
@@ -1201,6 +1231,15 @@ func codecDecodeToTextFormat(codec Codec, m *Map, oid uint32, format int16, src
// PlanEncode returns an Encode plan for encoding value into PostgreSQL format for oid and format. If no plan can be
// found then nil is returned.
func (m *Map) PlanEncode(oid uint32, format int16, value any) EncodePlan {
return m.planEncodeDepth(oid, format, value, 0)
}
func (m *Map) planEncodeDepth(oid uint32, format int16, value any, depth int) EncodePlan {
// Guard against infinite recursion.
if depth > 8 {
return nil
}
oidMemo := m.memoizedEncodePlans[oid]
if oidMemo == nil {
oidMemo = make(map[reflect.Type][2]EncodePlan)
@@ -1210,7 +1249,7 @@ func (m *Map) PlanEncode(oid uint32, format int16, value any) EncodePlan {
typeMemo := oidMemo[targetReflectType]
plan := typeMemo[format]
if plan == nil {
plan = m.planEncode(oid, format, value)
plan = m.planEncode(oid, format, value, depth)
typeMemo[format] = plan
oidMemo[targetReflectType] = typeMemo
}
@@ -1218,7 +1257,7 @@ func (m *Map) PlanEncode(oid uint32, format int16, value any) EncodePlan {
return plan
}
func (m *Map) planEncode(oid uint32, format int16, value any) EncodePlan {
func (m *Map) planEncode(oid uint32, format int16, value any, depth int) EncodePlan {
if format == TextFormatCode {
switch value.(type) {
case string:
@@ -1249,7 +1288,7 @@ func (m *Map) planEncode(oid uint32, format int16, value any) EncodePlan {
for _, f := range m.TryWrapEncodePlanFuncs {
if wrapperPlan, nextValue, ok := f(value); ok {
if nextPlan := m.PlanEncode(oid, format, nextValue); nextPlan != nil {
if nextPlan := m.planEncodeDepth(oid, format, nextValue, depth+1); nextPlan != nil {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan
}

View File

@@ -90,6 +90,7 @@ func initDefaultMap() {
defaultMap.RegisterType(&Type{Name: "varbit", OID: VarbitOID, Codec: BitsCodec{}})
defaultMap.RegisterType(&Type{Name: "varchar", OID: VarcharOID, Codec: TextCodec{}})
defaultMap.RegisterType(&Type{Name: "xid", OID: XIDOID, Codec: Uint32Codec{}})
defaultMap.RegisterType(&Type{Name: "xid8", OID: XID8OID, Codec: Uint64Codec{}})
defaultMap.RegisterType(&Type{Name: "xml", OID: XMLOID, Codec: &XMLCodec{Marshal: xml.Marshal, Unmarshal: xml.Unmarshal}})
// Range types
@@ -155,6 +156,7 @@ func initDefaultMap() {
defaultMap.RegisterType(&Type{Name: "_varbit", OID: VarbitArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[VarbitOID]}})
defaultMap.RegisterType(&Type{Name: "_varchar", OID: VarcharArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[VarcharOID]}})
defaultMap.RegisterType(&Type{Name: "_xid", OID: XIDArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[XIDOID]}})
defaultMap.RegisterType(&Type{Name: "_xid8", OID: XID8ArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[XID8OID]}})
defaultMap.RegisterType(&Type{Name: "_xml", OID: XMLArrayOID, Codec: &ArrayCodec{ElementType: defaultMap.oidToType[XMLOID]}})
// Integer types that directly map to a PostgreSQL type

View File

@@ -104,8 +104,8 @@ func (ts *Timestamp) UnmarshalJSON(b []byte) error {
case "-infinity":
*ts = Timestamp{Valid: true, InfinityModifier: -Infinity}
default:
// PostgreSQL uses ISO 8601 for to_json function and casting from a string to timestamptz
tim, err := time.Parse(time.RFC3339Nano, *s)
// PostgreSQL uses ISO 8601 wihout timezone for to_json function and casting from a string to timestampt
tim, err := time.Parse(time.RFC3339Nano, *s+"Z")
if err != nil {
return err
}
@@ -225,7 +225,6 @@ func discardTimeZone(t time.Time) time.Time {
}
func (c *TimestampCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
switch target.(type) {

322
vendor/github.com/jackc/pgx/v5/pgtype/uint64.go generated vendored Normal file
View File

@@ -0,0 +1,322 @@
package pgtype
import (
"database/sql/driver"
"encoding/binary"
"fmt"
"math"
"strconv"
"github.com/jackc/pgx/v5/internal/pgio"
)
type Uint64Scanner interface {
ScanUint64(v Uint64) error
}
type Uint64Valuer interface {
Uint64Value() (Uint64, error)
}
// Uint64 is the core type that is used to represent PostgreSQL types such as XID8.
type Uint64 struct {
Uint64 uint64
Valid bool
}
func (n *Uint64) ScanUint64(v Uint64) error {
*n = v
return nil
}
func (n Uint64) Uint64Value() (Uint64, error) {
return n, nil
}
// Scan implements the database/sql Scanner interface.
func (dst *Uint64) Scan(src any) error {
if src == nil {
*dst = Uint64{}
return nil
}
var n uint64
switch src := src.(type) {
case int64:
if src < 0 {
return fmt.Errorf("%d is less than the minimum value for Uint64", src)
}
n = uint64(src)
case string:
un, err := strconv.ParseUint(src, 10, 64)
if err != nil {
return err
}
n = un
default:
return fmt.Errorf("cannot scan %T", src)
}
*dst = Uint64{Uint64: n, Valid: true}
return nil
}
// Value implements the database/sql/driver Valuer interface.
func (src Uint64) Value() (driver.Value, error) {
if !src.Valid {
return nil, nil
}
// If the value is greater than the maximum value for int64, return it as a string instead of losing data or returning
// an error.
if src.Uint64 > math.MaxInt64 {
return strconv.FormatUint(src.Uint64, 10), nil
}
return int64(src.Uint64), nil
}
type Uint64Codec struct{}
func (Uint64Codec) FormatSupported(format int16) bool {
return format == TextFormatCode || format == BinaryFormatCode
}
func (Uint64Codec) PreferredFormat() int16 {
return BinaryFormatCode
}
func (Uint64Codec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan {
switch format {
case BinaryFormatCode:
switch value.(type) {
case uint64:
return encodePlanUint64CodecBinaryUint64{}
case Uint64Valuer:
return encodePlanUint64CodecBinaryUint64Valuer{}
case Int64Valuer:
return encodePlanUint64CodecBinaryInt64Valuer{}
}
case TextFormatCode:
switch value.(type) {
case uint64:
return encodePlanUint64CodecTextUint64{}
case Int64Valuer:
return encodePlanUint64CodecTextInt64Valuer{}
}
}
return nil
}
type encodePlanUint64CodecBinaryUint64 struct{}
func (encodePlanUint64CodecBinaryUint64) Encode(value any, buf []byte) (newBuf []byte, err error) {
v := value.(uint64)
return pgio.AppendUint64(buf, v), nil
}
type encodePlanUint64CodecBinaryUint64Valuer struct{}
func (encodePlanUint64CodecBinaryUint64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
v, err := value.(Uint64Valuer).Uint64Value()
if err != nil {
return nil, err
}
if !v.Valid {
return nil, nil
}
return pgio.AppendUint64(buf, v.Uint64), nil
}
type encodePlanUint64CodecBinaryInt64Valuer struct{}
func (encodePlanUint64CodecBinaryInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
v, err := value.(Int64Valuer).Int64Value()
if err != nil {
return nil, err
}
if !v.Valid {
return nil, nil
}
if v.Int64 < 0 {
return nil, fmt.Errorf("%d is less than minimum value for uint64", v.Int64)
}
return pgio.AppendUint64(buf, uint64(v.Int64)), nil
}
type encodePlanUint64CodecTextUint64 struct{}
func (encodePlanUint64CodecTextUint64) Encode(value any, buf []byte) (newBuf []byte, err error) {
v := value.(uint64)
return append(buf, strconv.FormatUint(uint64(v), 10)...), nil
}
type encodePlanUint64CodecTextUint64Valuer struct{}
func (encodePlanUint64CodecTextUint64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
v, err := value.(Uint64Valuer).Uint64Value()
if err != nil {
return nil, err
}
if !v.Valid {
return nil, nil
}
return append(buf, strconv.FormatUint(v.Uint64, 10)...), nil
}
type encodePlanUint64CodecTextInt64Valuer struct{}
func (encodePlanUint64CodecTextInt64Valuer) Encode(value any, buf []byte) (newBuf []byte, err error) {
v, err := value.(Int64Valuer).Int64Value()
if err != nil {
return nil, err
}
if !v.Valid {
return nil, nil
}
if v.Int64 < 0 {
return nil, fmt.Errorf("%d is less than minimum value for uint64", v.Int64)
}
return append(buf, strconv.FormatInt(v.Int64, 10)...), nil
}
func (Uint64Codec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
switch format {
case BinaryFormatCode:
switch target.(type) {
case *uint64:
return scanPlanBinaryUint64ToUint64{}
case Uint64Scanner:
return scanPlanBinaryUint64ToUint64Scanner{}
case TextScanner:
return scanPlanBinaryUint64ToTextScanner{}
}
case TextFormatCode:
switch target.(type) {
case *uint64:
return scanPlanTextAnyToUint64{}
case Uint64Scanner:
return scanPlanTextAnyToUint64Scanner{}
}
}
return nil
}
func (c Uint64Codec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) {
if src == nil {
return nil, nil
}
var n uint64
err := codecScan(c, m, oid, format, src, &n)
if err != nil {
return nil, err
}
return int64(n), nil
}
func (c Uint64Codec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) {
if src == nil {
return nil, nil
}
var n uint64
err := codecScan(c, m, oid, format, src, &n)
if err != nil {
return nil, err
}
return n, nil
}
type scanPlanBinaryUint64ToUint64 struct{}
func (scanPlanBinaryUint64ToUint64) Scan(src []byte, dst any) error {
if src == nil {
return fmt.Errorf("cannot scan NULL into %T", dst)
}
if len(src) != 8 {
return fmt.Errorf("invalid length for uint64: %v", len(src))
}
p := (dst).(*uint64)
*p = binary.BigEndian.Uint64(src)
return nil
}
type scanPlanBinaryUint64ToUint64Scanner struct{}
func (scanPlanBinaryUint64ToUint64Scanner) Scan(src []byte, dst any) error {
s, ok := (dst).(Uint64Scanner)
if !ok {
return ErrScanTargetTypeChanged
}
if src == nil {
return s.ScanUint64(Uint64{})
}
if len(src) != 8 {
return fmt.Errorf("invalid length for uint64: %v", len(src))
}
n := binary.BigEndian.Uint64(src)
return s.ScanUint64(Uint64{Uint64: n, Valid: true})
}
type scanPlanBinaryUint64ToTextScanner struct{}
func (scanPlanBinaryUint64ToTextScanner) Scan(src []byte, dst any) error {
s, ok := (dst).(TextScanner)
if !ok {
return ErrScanTargetTypeChanged
}
if src == nil {
return s.ScanText(Text{})
}
if len(src) != 8 {
return fmt.Errorf("invalid length for uint64: %v", len(src))
}
n := uint64(binary.BigEndian.Uint64(src))
return s.ScanText(Text{String: strconv.FormatUint(n, 10), Valid: true})
}
type scanPlanTextAnyToUint64Scanner struct{}
func (scanPlanTextAnyToUint64Scanner) Scan(src []byte, dst any) error {
s, ok := (dst).(Uint64Scanner)
if !ok {
return ErrScanTargetTypeChanged
}
if src == nil {
return s.ScanUint64(Uint64{})
}
n, err := strconv.ParseUint(string(src), 10, 64)
if err != nil {
return err
}
return s.ScanUint64(Uint64{Uint64: n, Valid: true})
}

View File

@@ -96,6 +96,14 @@ func (src UUID) Value() (driver.Value, error) {
return encodeUUID(src.Bytes), nil
}
func (src UUID) String() string {
if !src.Valid {
return ""
}
return encodeUUID(src.Bytes)
}
func (src UUID) MarshalJSON() ([]byte, error) {
if !src.Valid {
return []byte("null"), nil

View File

@@ -113,7 +113,7 @@ func (c *XMLCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPl
// https://github.com/jackc/pgx/issues/1691 -- ** anything else
if wrapperPlan, nextDst, ok := TryPointerPointerScanPlan(target); ok {
if nextPlan := m.planScan(oid, format, nextDst); nextPlan != nil {
if nextPlan := m.planScan(oid, format, nextDst, 0); nextPlan != nil {
if _, failed := nextPlan.(*scanPlanFail); !failed {
wrapperPlan.SetNext(nextPlan)
return wrapperPlan

View File

@@ -281,20 +281,20 @@ func NewWithConfig(ctx context.Context, config *Config) (*Pool, error) {
// ParseConfig builds a Config from connString. It parses connString with the same behavior as [pgx.ParseConfig] with the
// addition of the following variables:
//
// - pool_max_conns: integer greater than 0
// - pool_min_conns: integer 0 or greater
// - pool_max_conn_lifetime: duration string
// - pool_max_conn_idle_time: duration string
// - pool_health_check_period: duration string
// - pool_max_conn_lifetime_jitter: duration string
// - pool_max_conns: integer greater than 0 (default 4)
// - pool_min_conns: integer 0 or greater (default 0)
// - pool_max_conn_lifetime: duration string (default 1 hour)
// - pool_max_conn_idle_time: duration string (default 30 minutes)
// - pool_health_check_period: duration string (default 1 minute)
// - pool_max_conn_lifetime_jitter: duration string (default 0)
//
// See Config for definitions of these arguments.
//
// # Example Keyword/Value
// user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca pool_max_conns=10
// user=jack password=secret host=pg.example.com port=5432 dbname=mydb sslmode=verify-ca pool_max_conns=10 pool_max_conn_lifetime=1h30m
//
// # Example URL
// postgres://jack:secret@pg.example.com:5432/mydb?sslmode=verify-ca&pool_max_conns=10
// postgres://jack:secret@pg.example.com:5432/mydb?sslmode=verify-ca&pool_max_conns=10&pool_max_conn_lifetime=1h30m
func ParseConfig(connString string) (*Config, error) {
connConfig, err := pgx.ParseConfig(connString)
if err != nil {

15
vendor/github.com/jackc/pgx/v5/tx.go generated vendored
View File

@@ -48,6 +48,8 @@ type TxOptions struct {
// BeginQuery is the SQL query that will be executed to begin the transaction. This allows using non-standard syntax
// such as BEGIN PRIORITY HIGH with CockroachDB. If set this will override the other settings.
BeginQuery string
// CommitQuery is the SQL query that will be executed to commit the transaction.
CommitQuery string
}
var emptyTxOptions TxOptions
@@ -105,7 +107,10 @@ func (c *Conn) BeginTx(ctx context.Context, txOptions TxOptions) (Tx, error) {
return nil, err
}
return &dbTx{conn: c}, nil
return &dbTx{
conn: c,
commitQuery: txOptions.CommitQuery,
}, nil
}
// Tx represents a database transaction.
@@ -154,6 +159,7 @@ type dbTx struct {
conn *Conn
savepointNum int64
closed bool
commitQuery string
}
// Begin starts a pseudo nested transaction implemented with a savepoint.
@@ -177,7 +183,12 @@ func (tx *dbTx) Commit(ctx context.Context) error {
return ErrTxClosed
}
commandTag, err := tx.conn.Exec(ctx, "commit")
commandSQL := "commit"
if tx.commitQuery != "" {
commandSQL = tx.commitQuery
}
commandTag, err := tx.conn.Exec(ctx, commandSQL)
tx.closed = true
if err != nil {
if tx.conn.PgConn().TxStatus() != 'I' {

View File

@@ -45,6 +45,8 @@ type Complex interface {
// that supports the operators < <= >= >.
// If future releases of Go add new ordered types,
// this constraint will be modified to include them.
//
// This type is redundant since Go 1.21 introduced [cmp.Ordered].
type Ordered interface {
Integer | Float | ~string
}

View File

@@ -118,6 +118,7 @@ func (g *Group) TryGo(f func() error) bool {
// SetLimit limits the number of active goroutines in this group to at most n.
// A negative value indicates no limit.
// A limit of zero will prevent any new goroutines from being added.
//
// Any subsequent call to the Go method will block until it can add an active
// goroutine without exceeding the configured limit.

36
vendor/golang.org/x/sys/unix/auxv.go generated vendored Normal file
View File

@@ -0,0 +1,36 @@
// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.21 && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos)
package unix
import (
"syscall"
"unsafe"
)
//go:linkname runtime_getAuxv runtime.getAuxv
func runtime_getAuxv() []uintptr
// Auxv returns the ELF auxiliary vector as a sequence of key/value pairs.
// The returned slice is always a fresh copy, owned by the caller.
// It returns an error on non-ELF platforms, or if the auxiliary vector cannot be accessed,
// which happens in some locked-down environments and build modes.
func Auxv() ([][2]uintptr, error) {
vec := runtime_getAuxv()
vecLen := len(vec)
if vecLen == 0 {
return nil, syscall.ENOENT
}
if vecLen%2 != 0 {
return nil, syscall.EINVAL
}
result := make([]uintptr, vecLen)
copy(result, vec)
return unsafe.Slice((*[2]uintptr)(unsafe.Pointer(&result[0])), vecLen/2), nil
}

Some files were not shown because too many files have changed in this diff Show More