mirror of
https://github.com/crazy-max/diun.git
synced 2025-12-21 13:23:09 +01:00
chore(deps): bump github.com/dromara/carbon/v2 from 2.6.8 to 2.6.11
--- updated-dependencies: - dependency-name: github.com/dromara/carbon/v2 dependency-version: 2.6.11 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
2
go.mod
2
go.mod
@@ -17,7 +17,7 @@ require (
|
||||
github.com/docker/docker v27.3.1+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/dromara/carbon/v2 v2.6.8
|
||||
github.com/dromara/carbon/v2 v2.6.11
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.0
|
||||
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
|
||||
4
go.sum
4
go.sum
@@ -96,8 +96,8 @@ github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQ
|
||||
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dromara/carbon/v2 v2.6.8 h1:2iWFoekr7p5WAWb5NK7Edf4Co8GQKSinh24+osgGt2Y=
|
||||
github.com/dromara/carbon/v2 v2.6.8/go.mod h1:7GXqCUplwN1s1b4whGk2zX4+g4CMCoDIZzmjlyt0vLY=
|
||||
github.com/dromara/carbon/v2 v2.6.11 h1:wnAWZ+sbza1uXw3r05hExNSCaBPFaarWfUvYAX86png=
|
||||
github.com/dromara/carbon/v2 v2.6.11/go.mod h1:7GXqCUplwN1s1b4whGk2zX4+g4CMCoDIZzmjlyt0vLY=
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o=
|
||||
github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk=
|
||||
github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g=
|
||||
|
||||
22
vendor/github.com/dromara/carbon/v2/README.cn.md
generated
vendored
22
vendor/github.com/dromara/carbon/v2/README.cn.md
generated
vendored
@@ -1,22 +1,23 @@
|
||||
# Carbon #
|
||||
<p align="center" style="margin-bottom: -10px"><a href="https://carbon.go-pkg.com/zh" target="_blank"><img src="https://carbon.go-pkg.com/logo.svg?v=2.6.x" width="15%" alt="carbon" /></a></p>
|
||||
|
||||
[](https://github.com/dromara/carbon/releases)
|
||||
[](https://github.com/dromara/carbon/actions)
|
||||
[](https://goreportcard.com/report/github.com/dromara/carbon/v2)
|
||||
[](https://codecov.io/gh/dromara/carbon)
|
||||
[](https://pkg.go.dev/github.com/dromara/carbon/v2)
|
||||
<a href="https://hellogithub.com/repository/0eddd8c3469549b7b246f85a83d1c42e" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=0eddd8c3469549b7b246f85a83d1c42e&claim_uid=kKBvMpyxSgLhmJO&theme=small" alt="Featured|HelloGitHub" /></a>
|
||||
[](https://github.com/avelino/awesome-go#date-and-time)
|
||||
[](https://hellogithub.com/en/repository/dromara/carbon)
|
||||
[](https://github.com/dromara/carbon/blob/master/LICENSE)
|
||||
|
||||
简体中文 | [English](README.md) | [日本語](README.jp.md)
|
||||
简体中文 | [English](README.md) | [日本語](README.ja.md) | [한국어](README.ko.md)
|
||||
|
||||
## 项目简介
|
||||
|
||||
一个轻量级、语义化、对开发者友好的 `golang` 时间处理库,不依赖于 `任何` 第三方库, `100%` 单元测试覆盖率,已被 [awesome-go](https://github.com/yinggaozhen/awesome-go-cn#日期和时间 "awesome-go-cn") 和 [hello-github](https://hellogithub.com/repository/dromara/carbon "hello-github") 收录,并获得
|
||||
`Carbon` 是一个轻量级、语义化、对开发者友好的 `golang` 时间处理库,不依赖于 `任何` 第三方库, `100%` 单元测试覆盖率,已被 [awesome-go](https://github.com/yinggaozhen/awesome-go-cn#日期和时间 "awesome-go-cn") 和 [hello-github](https://hellogithub.com/repository/dromara/carbon "hello-github") 收录,并获得
|
||||
`gitee` 2024 年最有价值项目(`GVP`)和 `gitcode` 2024 年度开源摘星计划 (`G-Star`) 项目
|
||||
|
||||
<img src="https://gitee.com/dromara/carbon/raw/master/gvp.jpg" width="100%" alt="gvp"/>
|
||||
<img src="https://gitee.com/dromara/carbon/raw/master/gstar.jpg" width="100%" alt="g-star"/>
|
||||
<img src="https://carbon.go-pkg.com/gvp.jpg?v=2.6.x" width="100%" alt="gvp"/>
|
||||
<img src="https://carbon.go-pkg.com/gstar.jpg?v=2.6.x" width="100%" alt="g-star"/>
|
||||
|
||||
## 仓库地址
|
||||
|
||||
@@ -82,10 +83,7 @@ carbon.Parse("2020-07-05 13:14:15").SetLocale("zh-CN").DiffForHumans() // 1 月
|
||||
carbon.ClearTestNow()
|
||||
carbon.IsTestNow() // false
|
||||
```
|
||||
|
||||
## 文档
|
||||
|
||||
请访问 [carbon.go-pkg.com](https://carbon.go-pkg.com) 查看完整文档
|
||||
更多用法示例请查看 <a href="https://carbon.go-pkg.com/zh" target="_blank">官方文档</a>,性能测试报告请查看 [分析报告](test_report.cn.md)
|
||||
|
||||
## 参考项目
|
||||
|
||||
@@ -107,13 +105,13 @@ carbon.IsTestNow() // false
|
||||
## 赞助
|
||||
|
||||
`Carbon` 是一个非商业开源项目, 如果你想支持 `Carbon`,
|
||||
你可以为开发者 [购买一杯咖啡](https://www.gouguoyin.com/zanzhu.html)
|
||||
你可以为开发者 [购买一杯咖啡](https://carbon.go-pkg.com/zh/sponsor.html)
|
||||
|
||||
## 致谢
|
||||
|
||||
`Carbon`已获取免费的 JetBrains 开源许可证,在此表示感谢
|
||||
|
||||
<a href="https://www.jetbrains.com"><img src="https://foruda.gitee.com/images/1704325523163241662/1bf21f86_544375.png" height="100" alt="JetBrains"/></a>
|
||||
<a href="https://www.jetbrains.com" target="_blank"><img src="https://carbon.go-pkg.com/jetbrains.svg?v=2.6.x" height="50" alt="JetBrains"/></a>
|
||||
|
||||
## 开源协议
|
||||
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
# Carbon
|
||||
<p align="center" style="margin-bottom: -10px"><a href="https://carbon.go-pkg.com/zh" target="_blank"><img src="https://carbon.go-pkg.com/logo.svg?v=2.6.x" width="15%" alt="carbon" /></a></p>
|
||||
|
||||
[](https://github.com/dromara/carbon/releases)
|
||||
[](https://github.com/dromara/carbon/actions)
|
||||
[](https://goreportcard.com/report/github.com/dromara/carbon/v2)
|
||||
[](https://codecov.io/gh/dromara/carbon)
|
||||
[](https://pkg.go.dev/github.com/dromara/carbon/v2)
|
||||
<a href="https://hellogithub.com/en/repository/dromara/carbon" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=0eddd8c3469549b7b246f85a83d1c42e&claim_uid=kKBvMpyxSgLhmJO&theme=small" alt="Featured|HelloGitHub" /></a>
|
||||
[](https://github.com/avelino/awesome-go#date-and-time)
|
||||
[](https://hellogithub.com/en/repository/dromara/carbon)
|
||||
[](https://github.com/dromara/carbon/blob/master/LICENSE)
|
||||
|
||||
日本語 | [English](README.md) | [简体中文](README.cn.md)
|
||||
日本語 | [English](README.md) | [简体中文](README.cn.md) | [한국어](README.ko.md)
|
||||
|
||||
## イントロ
|
||||
|
||||
軽量、セマンティック、開発者に優しい `golang` 時間処理ライブラリ, `いかなる`第三者ライブラリにも依存せず、` 100%`ユニットテストカバレッジ率は、[awesome-go](https://github.com/avelino/awesome-go#date-and-time "awesome-go") と [hello-github](https://hellogithub.com/en/repository/dromara/carbon "hello-github") 収録
|
||||
`Carbon` は軽量、セマンティック、開発者に優しい `golang` 時間処理ライブラリ, `いかなる`第三者ライブラリにも依存せず、`100%`ユニットテストカバレッジ率は、[awesome-go](https://github.com/avelino/awesome-go#date-and-time "awesome-go") と [hello-github](https://hellogithub.com/en/repository/dromara/carbon "hello-github") 収録
|
||||
|
||||
## リポジトリ
|
||||
|
||||
@@ -75,6 +76,9 @@ carbon.Parse("2020-07-05 13:14:15").SetLocale("jp").DiffForHumans() // 1 ヶ月
|
||||
carbon.ClearTestNow()
|
||||
carbon.IsTestNow() // false
|
||||
```
|
||||
詳細については <a href="https://carbon.go-pkg.com/ja" target="_blank">公式ドキュメント</a>
|
||||
|
||||
より多くの使用例については、<a href="https://carbon.go-pkg.com/ja" target="_blank">公式ドキュメント</a>をご覧ください。性能テストレポートについては、[分析报告](test_report.ja.md)をご参照ください
|
||||
|
||||
## リファレンス
|
||||
|
||||
@@ -94,14 +98,14 @@ carbon.IsTestNow() // false
|
||||
|
||||
## スポンサー
|
||||
|
||||
`Carbon` は非営利のオープンソースプロジェクトです,`Carbon` をサポートしたい場合は、開発者のために [コーヒーを1杯購入](https://opencollective.com/go-carbon) できます
|
||||
`Carbon` は非営利のオープンソースプロジェクトです,`Carbon` をサポートしたい場合は、開発者のために [コーヒーを1杯購入](https://carbon.go-pkg.com/ja/sponsor.html) できます
|
||||
|
||||
## 謝辞
|
||||
|
||||
`Carbon` は無料の JetBrains オープンソースライセンスを取得しました,これに感謝します
|
||||
|
||||
<a href="https://www.jetbrains.com"><img src="https://foruda.gitee.com/images/1704325523163241662/1bf21f86_544375.png" height="100" alt="JetBrains"/></a>
|
||||
<a href="https://www.jetbrains.com" target="_blank"><img src="https://carbon.go-pkg.com/jetbrains.svg?v=2.6.x" height="50" alt="JetBrains"/></a>
|
||||
|
||||
## オープンソースプロトコル
|
||||
|
||||
`Carbon` は `MIT` オープンソースプロトコルに準拠しており、詳細は[LICENSE](./LICENSE)を参照してください
|
||||
`Carbon` は `MIT` オープンソースプロトコルに準拠しており、詳細は [LICENSE](./LICENSE) を参照してください
|
||||
110
vendor/github.com/dromara/carbon/v2/README.ko.md
generated
vendored
Normal file
110
vendor/github.com/dromara/carbon/v2/README.ko.md
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
<p align="center" style="margin-bottom: -10px"><a href="https://carbon.go-pkg.com/ko" target="_blank"><img src="https://carbon.go-pkg.com/logo.svg?v=2.6.x" width="15%" alt="carbon" /></a></p>
|
||||
|
||||
[](https://github.com/dromara/carbon/releases)
|
||||
[](https://github.com/dromara/carbon/actions)
|
||||
[](https://goreportcard.com/report/github.com/dromara/carbon/v2)
|
||||
[](https://codecov.io/gh/dromara/carbon)
|
||||
[](https://pkg.go.dev/github.com/dromara/carbon/v2)
|
||||
[](https://github.com/avelino/awesome-go#date-and-time)
|
||||
[](https://hellogithub.com/en/repository/dromara/carbon)
|
||||
[](https://github.com/dromara/carbon/blob/master/LICENSE)
|
||||
|
||||
한국어 | [English](README.md) | [简体中文](README.zh.md) | [日本語](README.ja.md)
|
||||
|
||||
## 소개
|
||||
|
||||
`Carbon`은 `golang`을 위한 간단하고, 의미론적이며, 개발자 친화적인 시간 패키지입니다. `100%` 단위 테스트 커버리지를 제공하며, `어떤` 서드파티 패키지에도 의존하지 않으며, [awesome-go](https://github.com/avelino/awesome-go#date-and-time "awesome-go")와 [hello-github](https://hellogithub.com/en/repository/dromara/carbon "hello-github")에 포함되어 있습니다.
|
||||
|
||||
## 저장소
|
||||
|
||||
[github.com/dromara/carbon](https://github.com/dromara/carbon "github.com/dromara/carbon")
|
||||
|
||||
[gitee.com/dromara/carbon](https://gitee.com/dromara/carbon "gitee.com/dromara/carbon")
|
||||
|
||||
[gitcode.com/dromara/carbon](https://gitcode.com/dromara/carbon "gitcode.com/dromara/carbon")
|
||||
|
||||
## 빠른 시작
|
||||
|
||||
### 설치
|
||||
> go version >= 1.21
|
||||
|
||||
```go
|
||||
// GitHub를 통해
|
||||
go get -u github.com/dromara/carbon/v2
|
||||
import "github.com/dromara/carbon/v2"
|
||||
|
||||
// Gitee를 통해
|
||||
go get -u gitee.com/dromara/carbon/v2
|
||||
import "gitee.com/dromara/carbon/v2"
|
||||
|
||||
// GitCode를 통해
|
||||
go get -u gitcode.com/dromara/carbon/v2
|
||||
import "gitee.com/dromara/gitcode/v2"
|
||||
```
|
||||
|
||||
`Carbon`은 [dromara](https://dromara.org/ "dromara") 조직에 기부되었으며, 저장소 URL이 변경되었습니다. 이전에 사용하던 저장소가 `golang-module/carbon`이었다면, `go.mod`에서 원래 저장소를 새 저장소로 교체하거나 다음 명령을 실행하세요:
|
||||
|
||||
```go
|
||||
go mod edit -replace github.com/golang-module/carbon/v2 = github.com/dromara/carbon/v2
|
||||
```
|
||||
|
||||
### 사용 예시
|
||||
기본 시간대는 `UTC`이고, 언어 로케일은 `English`이며, 주의 시작일은 `Monday`이고 주말은 `Saturday`와 `Sunday`입니다.
|
||||
|
||||
```go
|
||||
carbon.SetTestNow(carbon.Parse("2020-08-05 13:14:15.999999999"))
|
||||
carbon.IsTestNow() // true
|
||||
|
||||
carbon.Now().ToString() // 2020-08-05 13:14:15.999999999 +0000 UTC
|
||||
carbon.Yesterday().ToString() // 2020-08-04 13:14:15.999999999 +0000 UTC
|
||||
carbon.Tomorrow().ToString() // 2020-08-06 13:14:15.999999999 +0000 UTC
|
||||
|
||||
carbon.Parse("2020-08-05 13:14:15").ToString() // 2020-08-05 13:14:15 +0000 UTC
|
||||
carbon.Parse("2022-03-08T03:01:14-07:00").ToString() // 2022-03-08 10:01:14 +0000 UTC
|
||||
|
||||
carbon.ParseByLayout("It is 2020-08-05 13:14:15", "It is 2006-01-02 15:04:05").ToString() // 2020-08-05 13:14:15 +0000 UTC
|
||||
carbon.ParseByFormat("It is 2020-08-05 13:14:15", "\\I\\t \\i\\s Y-m-d H:i:s").ToString() // 2020-08-05 13:14:15 +0000 UTC
|
||||
|
||||
carbon.CreateFromDate(2020, 8, 5).ToString() // 2020-08-05 00:00:00 +0000 UTC
|
||||
carbon.CreateFromTime(13, 14, 15).ToString() // 2020-08-05 13:14:15 +0000 UTC
|
||||
carbon.CreateFromDateTime(2020, 8, 5, 13, 14, 15).ToString() // 2020-08-05 13:14:15 +0000 UTC
|
||||
carbon.CreateFromTimestamp(1596633255).ToString() // 2020-08-05 13:14:15 +0000 UTC
|
||||
|
||||
carbon.Parse("2020-07-05 13:14:15").DiffForHumans() // 1 month before
|
||||
carbon.Parse("2020-07-05 13:14:15").SetLocale("zh-CN").DiffForHumans() // 1 月前
|
||||
|
||||
carbon.ClearTestNow()
|
||||
carbon.IsTestNow() // false
|
||||
```
|
||||
|
||||
더 많은 사용 예시는 <a href="https://carbon.go-pkg.com/ko" target="_blank">공식 문서</a>를 참조하세요. 성능 테스트 보고서는 [분석 보고서](test_report.ko.md)를 참조하세요.
|
||||
|
||||
## 참고 자료
|
||||
|
||||
* [briannesbitt/carbon](https://github.com/briannesbitt/Carbon)
|
||||
* [nodatime/nodatime](https://github.com/nodatime/nodatime)
|
||||
* [jinzhu/now](https://github.com/jinzhu/now)
|
||||
* [goframe/gtime](https://github.com/gogf/gf/tree/master/os/gtime)
|
||||
* [jodaOrg/joda-time](https://github.com/jodaOrg/joda-time)
|
||||
* [arrow-py/arrow](https://github.com/arrow-py/arrow)
|
||||
* [moment/moment](https://github.com/moment/moment)
|
||||
* [iamkun/dayjs](https://github.com/iamkun/dayjs)
|
||||
|
||||
## 기여자
|
||||
`Carbon`에 기여한 모든 분들께 감사드립니다:
|
||||
|
||||
<a href="https://github.com/dromara/carbon/graphs/contributors"><img src="https://contrib.rocks/image?repo=dromara/carbon&max=100&columns=16" /></a>
|
||||
|
||||
## 스폰서
|
||||
|
||||
`Carbon`은 비상업적 오픈소스 프로젝트입니다. `Carbon`을 지원하고 싶으시다면 개발자에게 [커피 한 잔을 사주세요](https://carbon.go-pkg.com/ko/sponsor.html).
|
||||
|
||||
## 감사의 말
|
||||
|
||||
`Carbon`은 JetBrains 오픈소스 라이선스의 무료 GoLand로 개발되었습니다. 여기서 감사의 말을 전하고 싶습니다.
|
||||
|
||||
<a href="https://www.jetbrains.com" target="_blank"><img src="https://carbon.go-pkg.com/jetbrains.svg?v=2.6.x" height="50" alt="JetBrains"/></a>
|
||||
|
||||
## 라이선스
|
||||
|
||||
`Carbon`은 `MIT` 라이선스 하에 제공됩니다. 자세한 내용은 [LICENSE](./LICENSE) 파일을 참조하세요.
|
||||
17
vendor/github.com/dromara/carbon/v2/README.md
generated
vendored
17
vendor/github.com/dromara/carbon/v2/README.md
generated
vendored
@@ -1,18 +1,19 @@
|
||||
# Carbon
|
||||
<p align="center" style="margin-bottom: -10px"><a href="https://carbon.go-pkg.com/zh" target="_blank"><img src="https://carbon.go-pkg.com/logo.svg?v=2.6.x" width="15%" alt="carbon" /></a></p>
|
||||
|
||||
[](https://github.com/dromara/carbon/releases)
|
||||
[](https://github.com/dromara/carbon/actions)
|
||||
[](https://goreportcard.com/report/github.com/dromara/carbon/v2)
|
||||
[](https://codecov.io/gh/dromara/carbon)
|
||||
[](https://pkg.go.dev/github.com/dromara/carbon/v2)
|
||||
<a href="https://hellogithub.com/en/repository/dromara/carbon" target="_blank"><img src="https://api.hellogithub.com/v1/widgets/recommend.svg?rid=0eddd8c3469549b7b246f85a83d1c42e&claim_uid=kKBvMpyxSgLhmJO&theme=small" alt="Featured|HelloGitHub" /></a>
|
||||
[](https://github.com/avelino/awesome-go#date-and-time)
|
||||
[](https://hellogithub.com/en/repository/dromara/carbon)
|
||||
[](https://github.com/dromara/carbon/blob/master/LICENSE)
|
||||
|
||||
English | [简体中文](README.cn.md) | [日本語](README.jp.md)
|
||||
English | [简体中文](README.cn.md) | [日本語](README.ja.md) | [한국어](README.ko.md)
|
||||
|
||||
## Introduction
|
||||
|
||||
A simple, semantic and developer-friendly time package for `golang`, `100%` unit test coverage, doesn't depend on `any` third-party package and has been included by [awesome-go](https://github.com/avelino/awesome-go#date-and-time "awesome-go") and [hello-github](https://hellogithub.com/en/repository/dromara/carbon "hello-github")
|
||||
`Carbon` is a simple, semantic and developer-friendly time package for `golang`, `100%` unit test coverage, doesn't depend on `any` third-party package and has been included by [awesome-go](https://github.com/avelino/awesome-go#date-and-time "awesome-go") and [hello-github](https://hellogithub.com/en/repository/dromara/carbon "hello-github")
|
||||
|
||||
## Repository
|
||||
|
||||
@@ -79,9 +80,9 @@ carbon.ClearTestNow()
|
||||
carbon.IsTestNow() // false
|
||||
```
|
||||
|
||||
## Documentation
|
||||
For more usage examples, please refer to <a href="https://carbon.go-pkg.com/zh" target="_blank">official document</a>.
|
||||
|
||||
For full documentation, please visit [carbon.go-pkg.com](https://carbon.go-pkg.com)
|
||||
For performance test reports, please refer to [analysis report](test_report.en.md)
|
||||
|
||||
## References
|
||||
|
||||
@@ -101,14 +102,14 @@ Thanks to all the following who contributed to `Carbon`:
|
||||
|
||||
## Sponsors
|
||||
|
||||
`Carbon` is a non-commercial open source project. If you want to support `Carbon`, you can [buy a cup of coffee](https://opencollective.com/go-carbon) for developer.
|
||||
`Carbon` is a non-commercial open source project. If you want to support `Carbon`, you can [buy a cup of coffee](https://carbon.go-pkg.com/sponsor.html) for developer.
|
||||
|
||||
## Thanks
|
||||
|
||||
`Carbon` had been being developed with GoLand under the free JetBrains Open Source license, I would like to express my
|
||||
thanks here.
|
||||
|
||||
<a href="https://www.jetbrains.com"><img src="https://foruda.gitee.com/images/1704325523163241662/1bf21f86_544375.png" height="100" alt="JetBrains"/></a>
|
||||
<a href="https://www.jetbrains.com" target="_blank"><img src="https://carbon.go-pkg.com/jetbrains.svg?v=2.6.x" height="50" alt="JetBrains"/></a>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
43
vendor/github.com/dromara/carbon/v2/boundary.go
generated
vendored
43
vendor/github.com/dromara/carbon/v2/boundary.go
generated
vendored
@@ -5,7 +5,7 @@ func (c *Carbon) StartOfCentury() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
return c.create(c.Year()/YearsPerCentury*YearsPerCentury, 1, 1, 0, 0, 0, 0)
|
||||
return c.create(c.Year()/YearsPerCentury*YearsPerCentury, MinMonth, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfCentury returns a Carbon instance for end of the century.
|
||||
@@ -13,7 +13,7 @@ func (c *Carbon) EndOfCentury() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
return c.create(c.Year()/YearsPerCentury*YearsPerCentury+99, 12, 31, 23, 59, 59, 999999999)
|
||||
return c.create(c.Year()/YearsPerCentury*YearsPerCentury+99, MaxMonth, MaxDay, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfDecade returns a Carbon instance for start of the decade.
|
||||
@@ -21,7 +21,7 @@ func (c *Carbon) StartOfDecade() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
return c.create(c.Year()/YearsPerDecade*YearsPerDecade, 1, 1, 0, 0, 0, 0)
|
||||
return c.create(c.Year()/YearsPerDecade*YearsPerDecade, MinMonth, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfDecade returns a Carbon instance for end of the decade.
|
||||
@@ -29,7 +29,7 @@ func (c *Carbon) EndOfDecade() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
return c.create(c.Year()/YearsPerDecade*YearsPerDecade+9, 12, 31, 23, 59, 59, 999999999)
|
||||
return c.create(c.Year()/YearsPerDecade*YearsPerDecade+9, MaxMonth, MaxDay, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfYear returns a Carbon instance for start of the year.
|
||||
@@ -37,7 +37,7 @@ func (c *Carbon) StartOfYear() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
return c.create(c.Year(), 1, 1, 0, 0, 0, 0)
|
||||
return c.create(c.Year(), MinMonth, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfYear returns a Carbon instance for end of the year.
|
||||
@@ -45,7 +45,7 @@ func (c *Carbon) EndOfYear() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
return c.create(c.Year(), 12, 31, 23, 59, 59, 999999999)
|
||||
return c.create(c.Year(), MaxMonth, MaxDay, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfQuarter returns a Carbon instance for start of the quarter.
|
||||
@@ -53,8 +53,8 @@ func (c *Carbon) StartOfQuarter() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
year, quarter, day := c.Year(), c.Quarter(), 1
|
||||
return c.create(year, 3*quarter-2, day, 0, 0, 0, 0)
|
||||
year, quarter := c.Year(), c.Quarter()
|
||||
return c.create(year, 3*quarter-2, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfQuarter returns a Carbon instance for end of the quarter.
|
||||
@@ -62,14 +62,15 @@ func (c *Carbon) EndOfQuarter() *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
year, quarter, day := c.Year(), c.Quarter(), 30
|
||||
year, quarter := c.Year(), c.Quarter()
|
||||
var day int
|
||||
switch quarter {
|
||||
case 1, 4:
|
||||
day = 31
|
||||
day = MaxDay
|
||||
case 2, 3:
|
||||
day = 30
|
||||
}
|
||||
return c.create(year, 3*quarter, day, 23, 59, 59, 999999999)
|
||||
return c.create(year, 3*quarter, day, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfMonth returns a Carbon instance for start of the month.
|
||||
@@ -78,7 +79,7 @@ func (c *Carbon) StartOfMonth() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, _ := c.Date()
|
||||
return c.create(year, month, 1, 0, 0, 0, 0)
|
||||
return c.create(year, month, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfMonth returns a Carbon instance for end of the month.
|
||||
@@ -87,7 +88,7 @@ func (c *Carbon) EndOfMonth() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, _ := c.Date()
|
||||
return c.create(year, month+1, 0, 23, 59, 59, 999999999)
|
||||
return c.create(year, month+1, 0, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfWeek returns a Carbon instance for start of the week.
|
||||
@@ -120,7 +121,7 @@ func (c *Carbon) StartOfDay() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day := c.Date()
|
||||
return c.create(year, month, day, 0, 0, 0, 0)
|
||||
return c.create(year, month, day, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfDay returns a Carbon instance for end of the day.
|
||||
@@ -129,7 +130,7 @@ func (c *Carbon) EndOfDay() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day := c.Date()
|
||||
return c.create(year, month, day, 23, 59, 59, 999999999)
|
||||
return c.create(year, month, day, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfHour returns a Carbon instance for start of the hour.
|
||||
@@ -138,7 +139,7 @@ func (c *Carbon) StartOfHour() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day := c.Date()
|
||||
return c.create(year, month, day, c.Hour(), 0, 0, 0)
|
||||
return c.create(year, month, day, c.Hour(), MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfHour returns a Carbon instance for end of the hour.
|
||||
@@ -147,7 +148,7 @@ func (c *Carbon) EndOfHour() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day := c.Date()
|
||||
return c.create(year, month, day, c.Hour(), 59, 59, 999999999)
|
||||
return c.create(year, month, day, c.Hour(), MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfMinute returns a Carbon instance for start of the minute.
|
||||
@@ -156,7 +157,7 @@ func (c *Carbon) StartOfMinute() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day, hour, minute, _ := c.DateTime()
|
||||
return c.create(year, month, day, hour, minute, 0, 0)
|
||||
return c.create(year, month, day, hour, minute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfMinute returns a Carbon instance for end of the minute.
|
||||
@@ -165,7 +166,7 @@ func (c *Carbon) EndOfMinute() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day, hour, minute, _ := c.DateTime()
|
||||
return c.create(year, month, day, hour, minute, 59, 999999999)
|
||||
return c.create(year, month, day, hour, minute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// StartOfSecond returns a Carbon instance for start of the second.
|
||||
@@ -174,7 +175,7 @@ func (c *Carbon) StartOfSecond() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day, hour, minute, second := c.DateTime()
|
||||
return c.create(year, month, day, hour, minute, second, 0)
|
||||
return c.create(year, month, day, hour, minute, second, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfSecond returns a Carbon instance for end of the second.
|
||||
@@ -183,5 +184,5 @@ func (c *Carbon) EndOfSecond() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, month, day, hour, minute, second := c.DateTime()
|
||||
return c.create(year, month, day, hour, minute, second, 999999999)
|
||||
return c.create(year, month, day, hour, minute, second, MaxNanosecond)
|
||||
}
|
||||
|
||||
24
vendor/github.com/dromara/carbon/v2/calendar.go
generated
vendored
24
vendor/github.com/dromara/carbon/v2/calendar.go
generated
vendored
@@ -1,6 +1,7 @@
|
||||
package carbon
|
||||
|
||||
import (
|
||||
"github.com/dromara/carbon/v2/calendar/hebrew"
|
||||
"github.com/dromara/carbon/v2/calendar/julian"
|
||||
"github.com/dromara/carbon/v2/calendar/lunar"
|
||||
"github.com/dromara/carbon/v2/calendar/persian"
|
||||
@@ -70,3 +71,26 @@ func CreateFromPersian(year, month, day int) *Carbon {
|
||||
}
|
||||
return NewCarbon(p.ToGregorian(DefaultTimezone).Time)
|
||||
}
|
||||
|
||||
// Hebrew converts Carbon instance to Hebrew instance.
|
||||
func (c *Carbon) Hebrew() *hebrew.Hebrew {
|
||||
if c.IsNil() {
|
||||
return nil
|
||||
}
|
||||
if c.IsZero() || c.IsEmpty() {
|
||||
return &hebrew.Hebrew{}
|
||||
}
|
||||
if c.HasError() {
|
||||
return &hebrew.Hebrew{Error: c.Error}
|
||||
}
|
||||
return hebrew.FromStdTime(c.StdTime())
|
||||
}
|
||||
|
||||
// CreateFromHebrew creates a Carbon instance from Hebrew date.
|
||||
func CreateFromHebrew(year, month, day int) *Carbon {
|
||||
h := hebrew.NewHebrew(year, month, day)
|
||||
if h.Error != nil {
|
||||
return &Carbon{isEmpty: true}
|
||||
}
|
||||
return NewCarbon(h.ToGregorian(DefaultTimezone).Time)
|
||||
}
|
||||
|
||||
11
vendor/github.com/dromara/carbon/v2/calendar/gregorian.go
generated
vendored
11
vendor/github.com/dromara/carbon/v2/calendar/gregorian.go
generated
vendored
@@ -21,3 +21,14 @@ func (g *Gregorian) String() string {
|
||||
}
|
||||
return g.Time.String()
|
||||
}
|
||||
|
||||
func (g *Gregorian) IsLeapYear() bool {
|
||||
if g == nil || g.Error != nil {
|
||||
return false
|
||||
}
|
||||
year := g.Time.Year()
|
||||
if year%400 == 0 || (year%4 == 0 && year%100 != 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
351
vendor/github.com/dromara/carbon/v2/calendar/hebrew/hebrew.go
generated
vendored
Normal file
351
vendor/github.com/dromara/carbon/v2/calendar/hebrew/hebrew.go
generated
vendored
Normal file
@@ -0,0 +1,351 @@
|
||||
package hebrew
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/dromara/carbon/v2/calendar"
|
||||
)
|
||||
|
||||
type Locale string
|
||||
|
||||
const (
|
||||
EnLocale Locale = "en"
|
||||
HeLocale Locale = "he"
|
||||
defaultLocale = EnLocale
|
||||
hebrewEpoch = 347995.5
|
||||
)
|
||||
|
||||
var (
|
||||
EnMonths = []string{"Nisan", "Iyyar", "Sivan", "Tammuz", "Av", "Elul", "Tishri", "Heshvan", "Kislev", "Teveth", "Shevat", "Adar", "Adar Bet"}
|
||||
HeMonths = []string{"ניסן", "אייר", "סיוון", "תמוז", "אב", "אלול", "תשרי", "חשוון", "כסלו", "טבת", "שבט", "אדר", "אדר ב"}
|
||||
EnWeeks = []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
|
||||
HeWeeks = []string{"ראשון", "שני", "שלישי", "רביעי", "חמישי", "שישי", "שבת"}
|
||||
)
|
||||
|
||||
type Hebrew struct {
|
||||
year, month, day int
|
||||
Error error
|
||||
}
|
||||
|
||||
// NewHebrew creates a new Hebrew calendar instance with specified year, month, and day
|
||||
func NewHebrew(year, month, day int) *Hebrew {
|
||||
h := &Hebrew{year: year, month: month, day: day}
|
||||
if !h.IsValid() {
|
||||
h.Error = fmt.Errorf("invalid Hebrew date: %d-%d-%d", year, month, day)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// FromStdTime converts standard time to Hebrew calendar date
|
||||
func FromStdTime(t time.Time) *Hebrew {
|
||||
if t.IsZero() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Special handling for January 1, 1 CE
|
||||
if t.Year() == 1 && t.Month() == 1 && t.Day() == 1 {
|
||||
return &Hebrew{year: 3761, month: 10, day: 18}
|
||||
}
|
||||
|
||||
// Authoritative implementation: directly use Julian Day Number
|
||||
jdn := gregorian2jdn(t.Year(), int(t.Month()), t.Day())
|
||||
y, m, d := jdn2hebrew(jdn)
|
||||
return &Hebrew{year: y, month: m, day: d}
|
||||
}
|
||||
|
||||
// ToGregorian converts Hebrew date to Gregorian date
|
||||
func (h *Hebrew) ToGregorian(timezone ...string) *calendar.Gregorian {
|
||||
g := new(calendar.Gregorian)
|
||||
if h == nil {
|
||||
return g
|
||||
}
|
||||
loc := time.UTC
|
||||
if len(timezone) > 0 {
|
||||
loc, g.Error = time.LoadLocation(timezone[0])
|
||||
}
|
||||
if g.Error != nil {
|
||||
return g
|
||||
}
|
||||
jd := hebrew2jdn(h.year, h.month, h.day)
|
||||
year, month, day := jdn2gregorian(int(jd))
|
||||
g.Time = time.Date(year, time.Month(month), day, 12, 0, 0, 0, loc)
|
||||
return g
|
||||
}
|
||||
|
||||
// IsValid checks if the Hebrew date is valid
|
||||
func (h *Hebrew) IsValid() bool {
|
||||
if h == nil || h.Error != nil {
|
||||
return false
|
||||
}
|
||||
// Hebrew year range: 1-9999, including 3761 (corresponding to 1 CE)
|
||||
if h.year < 1 || h.year > 9999 || h.month < 1 || h.month > 13 || h.day < 1 || h.day > 31 {
|
||||
return false
|
||||
}
|
||||
// Check if month is within valid range for the year
|
||||
if h.month > getMonthsInYear(h.year) {
|
||||
return false
|
||||
}
|
||||
// Check if day is within valid range for the month
|
||||
if h.day > getDaysInMonth(h.year, h.month) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// IsLeapYear checks if the Hebrew year is a leap year
|
||||
func (h *Hebrew) IsLeapYear() bool {
|
||||
if !h.IsValid() {
|
||||
return false
|
||||
}
|
||||
return ((7*h.year + 1) % 19) < 7
|
||||
}
|
||||
|
||||
// Year returns the Hebrew year
|
||||
func (h *Hebrew) Year() int {
|
||||
if !h.IsValid() {
|
||||
return 0
|
||||
}
|
||||
return h.year
|
||||
}
|
||||
|
||||
// Month returns the Hebrew month (1-13, where 13 is Adar Bet in leap years)
|
||||
func (h *Hebrew) Month() int {
|
||||
if !h.IsValid() {
|
||||
return 0
|
||||
}
|
||||
return h.month
|
||||
}
|
||||
|
||||
// Day returns the day of the Hebrew month
|
||||
func (h *Hebrew) Day() int {
|
||||
if !h.IsValid() {
|
||||
return 0
|
||||
}
|
||||
return h.day
|
||||
}
|
||||
|
||||
// String returns the Hebrew date in "YYYY-MM-DD" format
|
||||
func (h *Hebrew) String() string {
|
||||
if !h.IsValid() {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%04d-%02d-%02d", h.year, h.month, h.day)
|
||||
}
|
||||
|
||||
// ToMonthString returns the Hebrew month name in the specified locale
|
||||
func (h *Hebrew) ToMonthString(locale ...Locale) string {
|
||||
if !h.IsValid() {
|
||||
return ""
|
||||
}
|
||||
loc := defaultLocale
|
||||
if len(locale) > 0 {
|
||||
loc = locale[0]
|
||||
}
|
||||
idx := h.month - 1
|
||||
switch loc {
|
||||
case EnLocale:
|
||||
if idx >= 0 && idx < len(EnMonths) {
|
||||
return EnMonths[idx]
|
||||
}
|
||||
case HeLocale:
|
||||
if idx >= 0 && idx < len(HeMonths) {
|
||||
return HeMonths[idx]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToWeekString returns the weekday name in the specified locale
|
||||
func (h *Hebrew) ToWeekString(locale ...Locale) string {
|
||||
if !h.IsValid() {
|
||||
return ""
|
||||
}
|
||||
loc := defaultLocale
|
||||
if len(locale) > 0 {
|
||||
loc = locale[0]
|
||||
}
|
||||
jdn := hebrew2jdn(h.year, h.month, h.day)
|
||||
weekday := int(math.Mod(jdn+17, 7))
|
||||
switch loc {
|
||||
case EnLocale:
|
||||
return EnWeeks[weekday]
|
||||
case HeLocale:
|
||||
return HeWeeks[weekday]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// gregorian2jdn converts Gregorian date to Julian Day Number
|
||||
func gregorian2jdn(year, month, day int) float64 {
|
||||
if month <= 2 {
|
||||
month += 12
|
||||
year--
|
||||
}
|
||||
jd := math.Floor(365.25*float64(year+4716)) +
|
||||
math.Floor(30.6001*float64(month+1)) +
|
||||
float64(day) - 1524.0
|
||||
if year*372+month*31+day >= 588829 {
|
||||
century := year / 100
|
||||
jd += float64(2 - century + century/4)
|
||||
}
|
||||
return jd - 1
|
||||
}
|
||||
|
||||
// jdn2gregorian converts Julian Day Number to Gregorian date
|
||||
func jdn2gregorian(jdn int) (year, month, day int) {
|
||||
jd := float64(jdn)
|
||||
a := int(jd)
|
||||
b := a + 1524
|
||||
c := int((float64(b) - 122.1) / 365.25)
|
||||
d := int(365.25 * float64(c))
|
||||
e := int((float64(b - d)) / 30.6001)
|
||||
day = b - d - int(30.6001*float64(e))
|
||||
if e < 14 {
|
||||
month = e - 1
|
||||
} else {
|
||||
month = e - 13
|
||||
}
|
||||
if month > 2 {
|
||||
year = c - 4716
|
||||
} else {
|
||||
year = c - 4715
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// jdn2hebrew converts Julian Day Number to Hebrew date
|
||||
func jdn2hebrew(jdn float64) (year, month, day int) {
|
||||
// Estimate year
|
||||
approx := int((jdn - hebrewEpoch) / 365.25)
|
||||
// Precisely locate year
|
||||
year = approx
|
||||
for jdn >= getJDNInYear(year+1) {
|
||||
year++
|
||||
}
|
||||
|
||||
// Determine month
|
||||
firstMonth := 1
|
||||
if jdn < hebrew2jdn(year, 1, 1) {
|
||||
firstMonth = 7
|
||||
}
|
||||
month = firstMonth
|
||||
|
||||
maxMonth := getMonthsInYear(year)
|
||||
for month < maxMonth && jdn >= hebrew2jdn(year, month, getDaysInMonth(year, month)) {
|
||||
month++
|
||||
}
|
||||
|
||||
day = int(jdn-hebrew2jdn(year, month, 1)) + 1
|
||||
maxDay := getDaysInMonth(year, month)
|
||||
if day > maxDay {
|
||||
day = maxDay
|
||||
}
|
||||
if day < 1 {
|
||||
day = 1
|
||||
}
|
||||
return year, month, day
|
||||
}
|
||||
|
||||
// hebrew2jdn converts Hebrew date to Julian Day Number using authoritative algorithm
|
||||
func hebrew2jdn(year, month, day int) float64 {
|
||||
jdn := getJDNInYear(year)
|
||||
|
||||
monthOffset := 0
|
||||
if month < 7 {
|
||||
for m := 7; m <= getMonthsInYear(year); m++ {
|
||||
monthOffset += getDaysInMonth(year, m)
|
||||
}
|
||||
for m := 1; m < month; m++ {
|
||||
monthOffset += getDaysInMonth(year, m)
|
||||
}
|
||||
} else {
|
||||
for m := 7; m < month; m++ {
|
||||
monthOffset += getDaysInMonth(year, m)
|
||||
}
|
||||
}
|
||||
|
||||
return jdn + float64(monthOffset) + float64(day-1)
|
||||
}
|
||||
|
||||
// isLeapYear checks if the Hebrew year is a leap year
|
||||
func isLeapYear(year int) bool {
|
||||
return ((7*year + 1) % 19) < 7
|
||||
}
|
||||
|
||||
// getMonthsFromEpoch calculates the number of months elapsed since the Hebrew epoch
|
||||
func getMonthsFromEpoch(year int) int {
|
||||
cycles := (year - 1) / 19
|
||||
yearInCycle := (year - 1) % 19
|
||||
return 235*cycles + 12*yearInCycle + (7*yearInCycle+1)/19
|
||||
}
|
||||
|
||||
// getJDNInYear calculates the Julian Day Number of Hebrew New Year (Tishri 1)
|
||||
func getJDNInYear(year int) float64 {
|
||||
months := getMonthsFromEpoch(year)
|
||||
parts := 204 + 793*(months%1080)
|
||||
hours := 5 + 12*months + 793*(months/1080) + (parts / 1080)
|
||||
day := 1 + 29*months + (hours / 24)
|
||||
parts = 1080*(hours%24) + (parts % 1080)
|
||||
|
||||
if parts >= 19440 {
|
||||
day++
|
||||
}
|
||||
|
||||
if (day%7 == 0) || (day%7 == 3) || (day%7 == 5) {
|
||||
day++
|
||||
}
|
||||
|
||||
if (day%7 == 2) && (parts >= 9924) && !isLeapYear(year) {
|
||||
day++
|
||||
}
|
||||
if (day%7 == 1) && (parts >= 16789) && isLeapYear(year-1) {
|
||||
day++
|
||||
}
|
||||
|
||||
return float64(day) + hebrewEpoch
|
||||
}
|
||||
|
||||
// getMonthsInYear calculates the number of months in a year
|
||||
func getMonthsInYear(year int) int {
|
||||
if isLeapYear(year) {
|
||||
return 13
|
||||
}
|
||||
return 12
|
||||
}
|
||||
|
||||
// getDaysInMonth calculates the number of days in a month
|
||||
func getDaysInMonth(year, month int) int {
|
||||
// Fixed 29-day months
|
||||
if month == 2 || month == 4 || month == 6 || month == 10 || month == 13 {
|
||||
return 29
|
||||
}
|
||||
|
||||
// Adar in non-leap years is 29 days
|
||||
if month == 12 && !isLeapYear(year) {
|
||||
return 29
|
||||
}
|
||||
|
||||
// Calculate total days in the year
|
||||
yearDays := int(getJDNInYear(year+1) - getJDNInYear(year))
|
||||
|
||||
// Heshvan (month 8)
|
||||
if month == 8 {
|
||||
if yearDays == 355 || yearDays == 385 {
|
||||
return 30
|
||||
}
|
||||
return 29
|
||||
}
|
||||
|
||||
// Kislev (month 9)
|
||||
if month == 9 {
|
||||
if yearDays == 354 || yearDays == 383 {
|
||||
return 29
|
||||
}
|
||||
return 30
|
||||
}
|
||||
|
||||
// Other months are 30 days
|
||||
return 30
|
||||
}
|
||||
6098
vendor/github.com/dromara/carbon/v2/calendar/hebrew/hebrew_test_data.json
generated
vendored
Normal file
6098
vendor/github.com/dromara/carbon/v2/calendar/hebrew/hebrew_test_data.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
160
vendor/github.com/dromara/carbon/v2/calendar/hebrew/test_report.cn.md
generated
vendored
Normal file
160
vendor/github.com/dromara/carbon/v2/calendar/hebrew/test_report.cn.md
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
# 希伯来历(Hebrew)测试报告
|
||||
|
||||
## 概述
|
||||
|
||||
本报告详细记录了 `calendar/hebrew` 包的测试情况,包括功能特性、测试覆盖情况、性能基准和质量评估结果。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
- **希伯来历日期创建与验证**:支持希伯来历日期的创建和有效性验证
|
||||
- **格里历转换**:希伯来历日期与格里历日期之间的双向转换
|
||||
- **闰月处理**:完整的闰月计算和验证机制(Adar Bet)
|
||||
- **时区支持**:支持不同时区的日期转换
|
||||
|
||||
### 格式化功能
|
||||
- **多语言支持**:支持英文和希伯来文两种语言环境
|
||||
- **月份名称**:英文月份名(Nisan, Iyyar, Sivan等)和希伯来文月份名(ניסן, אייר, סיוון等)
|
||||
- **星期名称**:英文星期名(Sunday, Monday等)和希伯来文星期名(ראשון, שני等)
|
||||
- **日期字符串**:生成"YYYY-MM-DD"格式的日期字符串
|
||||
|
||||
### 算法特性
|
||||
- **闰年判断**:基于希伯来历规则的闰年计算((year*7 + 1) % 19 < 7)
|
||||
- **月份天数**:动态计算每个月的天数(29或30天)
|
||||
- **年份天数**:计算希伯来历年份的总天数
|
||||
- **JDN转换**:基于儒略日数的精确日期转换
|
||||
|
||||
### 验证功能
|
||||
- **年份验证**:支持广泛的年份范围验证
|
||||
- **月份验证**:1-13月范围验证,包含闰月处理
|
||||
- **日期验证**:基于月份天数的日期有效性验证
|
||||
- **边界处理**:完善的边界条件和错误处理
|
||||
|
||||
## 测试覆盖
|
||||
|
||||
### 单元测试统计
|
||||
- **测试用例总数**:573 行测试代码
|
||||
- **代码覆盖率**:100.0% 语句覆盖
|
||||
- **测试通过率**:100% (所有测试用例通过)
|
||||
|
||||
### 测试分类
|
||||
1. **基础功能测试**
|
||||
- 从标准时间创建希伯来历日期
|
||||
- 希伯来历转格里历转换
|
||||
- 时区处理测试
|
||||
|
||||
2. **格式化功能测试**
|
||||
- 年份、月份、日期获取
|
||||
- 月份名称字符串转换(英文/希伯来文)
|
||||
- 星期名称字符串转换(英文/希伯来文)
|
||||
- 日期字符串格式化
|
||||
|
||||
3. **算法功能测试**
|
||||
- 闰年判断测试
|
||||
- JDN转换测试
|
||||
- 月份天数计算测试
|
||||
- 年份天数计算测试
|
||||
|
||||
4. **边界条件测试**
|
||||
- 零值处理
|
||||
- 无效输入处理
|
||||
- 边界年份测试
|
||||
- 错误时区处理
|
||||
|
||||
5. **权威数据验证**
|
||||
- 基于Python权威库的380个测试用例
|
||||
- 重要希伯来节日验证(Rosh Hashanah、Yom Kippur、Passover、Shavuot、Sukkot、Hanukkah、Purim等)
|
||||
- 闰月处理验证(Adar Bet)
|
||||
- 双向转换一致性验证
|
||||
|
||||
### 测试数据
|
||||
- **权威测试用例**:380个测试用例
|
||||
- **测试数据文件**:4,941行JSON数据
|
||||
- **覆盖年份范围**:5780-5800年
|
||||
- **重要节日覆盖**:所有主要希伯来节日
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 核心操作性能
|
||||
- **FromStdTime**:1,009 ns/op,48 B/op,1 allocs/op
|
||||
- **ToGregorian**:303.7 ns/op,120 B/op,4 allocs/op
|
||||
- **ToGregorianWithTimezone**:64,390 ns/op,1,456 B/op,14 allocs/op
|
||||
|
||||
### 格式化操作性能
|
||||
- **String**:139.4 ns/op,24 B/op,2 allocs/op
|
||||
- **ToMonthString**:0.6605 ns/op,0 B/op,0 allocs/op
|
||||
- **ToMonthStringEnLocale**:0.9880 ns/op,0 B/op,0 allocs/op
|
||||
- **ToMonthStringHeLocale**:1.152 ns/op,0 B/op,0 allocs/op
|
||||
- **ToWeekString**:382.6 ns/op,120 B/op,4 allocs/op
|
||||
|
||||
### 算法计算性能
|
||||
- **IsLeapYear**:0.9189 ns/op,0 B/op,0 allocs/op
|
||||
- **Year/Month/Day**:~0.328 ns/op,0 B/op,0 allocs/op
|
||||
- **Hebrew2Jdn**:151.7 ns/op,0 B/op,0 allocs/op
|
||||
- **Jdn2Hebrew**:1,035 ns/op,0 B/op,0 allocs/op
|
||||
- **Gregorian2Jdn**:1.124 ns/op,0 B/op,0 allocs/op
|
||||
|
||||
### 内部方法性能
|
||||
- **GetFirstDelay**:0.9158 ns/op,0 B/op,0 allocs/op
|
||||
- **GetSecondDelay**:10.75 ns/op,0 B/op,0 allocs/op
|
||||
- **GetMonthsInYear**:1.027 ns/op,0 B/op,0 allocs/op
|
||||
- **GetDaysInYear**:29.35 ns/op,0 B/op,0 allocs/op
|
||||
- **GetDaysInMonth**:20.51 ns/op,0 B/op,0 allocs/op
|
||||
|
||||
## 算法验证
|
||||
|
||||
### 权威性验证
|
||||
- **Python权威库**:基于convertdate库的hebrew模块
|
||||
- **测试用例数量**:380个权威测试用例
|
||||
- **验证范围**:5780-5800年希伯来历
|
||||
- **验证内容**:重要节日、月份第一天、闰月处理
|
||||
|
||||
### 算法特点
|
||||
- **基于JDN**:使用儒略日数作为中间转换标准
|
||||
- **精确计算**:支持高精度日期转换
|
||||
- **闰月处理**:完整的Adar Bet(第13月)处理
|
||||
- **边界处理**:完善的边界条件和错误处理
|
||||
|
||||
### 数据完整性
|
||||
- **月份映射**:完整的英文和希伯来文月份名称
|
||||
- **星期映射**:完整的英文和希伯来文星期名称
|
||||
- **算法常数**:希伯来历纪元(347995.5)
|
||||
- **闰年规则**:19年周期的梅顿循环
|
||||
|
||||
## 质量评估
|
||||
|
||||
### 代码质量
|
||||
- **覆盖率**:100% 语句覆盖率
|
||||
- **错误处理**:完善的nil指针和边界条件处理
|
||||
- **代码结构**:清晰的模块化设计
|
||||
- **文档注释**:详细的方法和常量注释
|
||||
|
||||
### 性能质量
|
||||
- **高效算法**:优化的JDN转换算法
|
||||
- **内存优化**:最小化内存分配
|
||||
- **并发安全**:无状态设计,支持并发使用
|
||||
- **时区支持**:完整的时区处理能力
|
||||
|
||||
### 功能完整性
|
||||
- **功能完备**:覆盖希伯来历所有核心功能
|
||||
- **接口友好**:简洁易用的API设计
|
||||
- **扩展性强**:支持多语言环境扩展
|
||||
- **兼容性好**:与Carbon库其他模块良好集成
|
||||
|
||||
### 可靠性评估
|
||||
- **权威验证**:通过Python权威库验证
|
||||
- **边界测试**:完善的边界条件测试
|
||||
- **错误处理**:健壮的错误处理机制
|
||||
- **一致性**:双向转换的一致性保证
|
||||
|
||||
## 结论
|
||||
|
||||
希伯来历模块是一个高质量、功能完备的希伯来历处理库,具有以下特点:
|
||||
|
||||
1. **技术先进**:采用最新的算法和最佳实践
|
||||
2. **功能完整**:覆盖希伯来历处理的所有核心需求
|
||||
3. **性能优异**:高效的算法实现和优化的内存使用
|
||||
4. **质量可靠**:100%测试覆盖率和权威验证
|
||||
5. **易于使用**:简洁的API设计和完善的文档
|
||||
|
||||
该模块为希伯来历处理提供了可靠的技术基础,适用于宗教、文化、教育和技术等多个应用场景,是Carbon日期时间库的重要组成部分。
|
||||
160
vendor/github.com/dromara/carbon/v2/calendar/hebrew/test_report.en.md
generated
vendored
Normal file
160
vendor/github.com/dromara/carbon/v2/calendar/hebrew/test_report.en.md
generated
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
# Hebrew Calendar Module Test Report
|
||||
|
||||
## Overview
|
||||
|
||||
This report details the testing status of the `calendar/hebrew` package, including functional features, test coverage, performance benchmarks, and quality assessment results.
|
||||
|
||||
## Functional Features
|
||||
|
||||
### Core Functions
|
||||
- **Hebrew Date Creation and Validation**: Support for creating and validating Hebrew calendar dates
|
||||
- **Gregorian Conversion**: Bidirectional conversion between Hebrew and Gregorian dates
|
||||
- **Leap Month Handling**: Complete leap month calculation and validation mechanism (Adar Bet)
|
||||
- **Timezone Support**: Date conversion support for different timezones
|
||||
|
||||
### Formatting Features
|
||||
- **Multi-language Support**: Support for English and Hebrew language environments
|
||||
- **Month Names**: English month names (Nisan, Iyyar, Sivan, etc.) and Hebrew month names (ניסן, אייר, סיוון, etc.)
|
||||
- **Weekday Names**: English weekday names (Sunday, Monday, etc.) and Hebrew weekday names (ראשון, שני, etc.)
|
||||
- **Date Strings**: Generate date strings in "YYYY-MM-DD" format
|
||||
|
||||
### Algorithm Features
|
||||
- **Leap Year Determination**: Leap year calculation based on Hebrew calendar rules ((year*7 + 1) % 19 < 7)
|
||||
- **Month Days**: Dynamic calculation of days in each month (29 or 30 days)
|
||||
- **Year Days**: Calculation of total days in Hebrew calendar years
|
||||
- **JDN Conversion**: Precise date conversion based on Julian Day Numbers
|
||||
|
||||
### Validation Features
|
||||
- **Year Validation**: Support for wide year range validation
|
||||
- **Month Validation**: 1-13 month range validation, including leap month handling
|
||||
- **Date Validation**: Date validity validation based on month days
|
||||
- **Boundary Handling**: Comprehensive boundary conditions and error handling
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Unit Test Statistics
|
||||
- **Total Test Cases**: 573 lines of test code
|
||||
- **Code Coverage**: 100.0% statement coverage
|
||||
- **Test Pass Rate**: 100% (all test cases pass)
|
||||
|
||||
### Test Categories
|
||||
1. **Basic Function Tests**
|
||||
- Hebrew date creation from standard time
|
||||
- Hebrew to Gregorian conversion
|
||||
- Timezone handling tests
|
||||
|
||||
2. **Formatting Function Tests**
|
||||
- Year, month, day retrieval
|
||||
- Month name string conversion (English/Hebrew)
|
||||
- Weekday name string conversion (English/Hebrew)
|
||||
- Date string formatting
|
||||
|
||||
3. **Algorithm Function Tests**
|
||||
- Leap year determination tests
|
||||
- JDN conversion tests
|
||||
- Month days calculation tests
|
||||
- Year days calculation tests
|
||||
|
||||
4. **Boundary Condition Tests**
|
||||
- Zero value handling
|
||||
- Invalid input handling
|
||||
- Boundary year tests
|
||||
- Error timezone handling
|
||||
|
||||
5. **Authority Data Validation**
|
||||
- 380 test cases based on Python authority library
|
||||
- Important Hebrew holiday validation (Rosh Hashanah, Yom Kippur, Passover, Shavuot, Sukkot, Hanukkah, Purim, etc.)
|
||||
- Leap month handling validation (Adar Bet)
|
||||
- Bidirectional conversion consistency validation
|
||||
|
||||
### Test Data
|
||||
- **Authority Test Cases**: 380 test cases
|
||||
- **Test Data File**: 4,941 lines of JSON data
|
||||
- **Coverage Year Range**: 5780-5800
|
||||
- **Important Holiday Coverage**: All major Hebrew holidays
|
||||
|
||||
## Performance Benchmarks
|
||||
|
||||
### Core Operation Performance
|
||||
- **FromStdTime**: 1,009 ns/op, 48 B/op, 1 allocs/op
|
||||
- **ToGregorian**: 303.7 ns/op, 120 B/op, 4 allocs/op
|
||||
- **ToGregorianWithTimezone**: 64,390 ns/op, 1,456 B/op, 14 allocs/op
|
||||
|
||||
### Formatting Operation Performance
|
||||
- **String**: 139.4 ns/op, 24 B/op, 2 allocs/op
|
||||
- **ToMonthString**: 0.6605 ns/op, 0 B/op, 0 allocs/op
|
||||
- **ToMonthStringEnLocale**: 0.9880 ns/op, 0 B/op, 0 allocs/op
|
||||
- **ToMonthStringHeLocale**: 1.152 ns/op, 0 B/op, 0 allocs/op
|
||||
- **ToWeekString**: 382.6 ns/op, 120 B/op, 4 allocs/op
|
||||
|
||||
### Algorithm Calculation Performance
|
||||
- **IsLeapYear**: 0.9189 ns/op, 0 B/op, 0 allocs/op
|
||||
- **Year/Month/Day**: ~0.328 ns/op, 0 B/op, 0 allocs/op
|
||||
- **Hebrew2Jdn**: 151.7 ns/op, 0 B/op, 0 allocs/op
|
||||
- **Jdn2Hebrew**: 1,035 ns/op, 0 B/op, 0 allocs/op
|
||||
- **Gregorian2Jdn**: 1.124 ns/op, 0 B/op, 0 allocs/op
|
||||
|
||||
### Internal Method Performance
|
||||
- **GetFirstDelay**: 0.9158 ns/op, 0 B/op, 0 allocs/op
|
||||
- **GetSecondDelay**: 10.75 ns/op, 0 B/op, 0 allocs/op
|
||||
- **GetMonthsInYear**: 1.027 ns/op, 0 B/op, 0 allocs/op
|
||||
- **GetDaysInYear**: 29.35 ns/op, 0 B/op, 0 allocs/op
|
||||
- **GetDaysInMonth**: 20.51 ns/op, 0 B/op, 0 allocs/op
|
||||
|
||||
## Algorithm Verification
|
||||
|
||||
### Authority Verification
|
||||
- **Python Authority Library**: Based on the `hebrew` module of the `convertdate` library
|
||||
- **Number of Test Cases**: 380 authoritative test cases
|
||||
- **Validation Range**: Hebrew calendar years 5780-5800
|
||||
- **Validation Content**: Important holidays, first day of months, leap month handling
|
||||
|
||||
### Algorithm Characteristics
|
||||
- **JDN-based**: Uses Julian Day Numbers as intermediate conversion standard
|
||||
- **Precise Calculation**: Supports high-precision date conversion
|
||||
- **Leap Month Handling**: Complete Adar Bet (13th month) processing
|
||||
- **Boundary Handling**: Comprehensive boundary conditions and error handling
|
||||
|
||||
### Data Integrity
|
||||
- **Month Mapping**: Complete English and Hebrew month names
|
||||
- **Weekday Mapping**: Complete English and Hebrew weekday names
|
||||
- **Algorithm Constants**: Hebrew calendar epoch (347995.5)
|
||||
- **Leap Year Rules**: 19-year Metonic cycle
|
||||
|
||||
## Quality Assessment
|
||||
|
||||
### Code Quality
|
||||
- **Coverage**: 100% statement coverage
|
||||
- **Error Handling**: Comprehensive `nil` pointer and boundary condition handling
|
||||
- **Code Structure**: Clear modular design
|
||||
- **Documentation**: Detailed method and constant documentation
|
||||
|
||||
### Performance Quality
|
||||
- **Efficient Algorithms**: Optimized JDN conversion algorithms
|
||||
- **Memory Optimization**: Minimal memory allocation
|
||||
- **Concurrency Safety**: Stateless design supporting concurrent usage
|
||||
- **Timezone Support**: Complete timezone handling capabilities
|
||||
|
||||
### Functional Completeness
|
||||
- **Complete Functionality**: Covers all core Hebrew calendar functions
|
||||
- **User-friendly Interface**: Clean and easy-to-use API design
|
||||
- **Extensibility**: Supports multi-language environment expansion
|
||||
- **Compatibility**: Good integration with other Carbon library modules
|
||||
|
||||
### Reliability Assessment
|
||||
- **Authority Verification**: Verified against Python authority library
|
||||
- **Boundary Testing**: Comprehensive boundary condition testing
|
||||
- **Error Handling**: Robust error handling mechanisms
|
||||
- **Consistency**: Bidirectional conversion consistency guarantee
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Hebrew calendar module is a high-quality, feature-complete Hebrew calendar processing library with the following characteristics:
|
||||
|
||||
1. **Technologically Advanced**: Adopts latest algorithms and best practices
|
||||
2. **Functionally Complete**: Covers all core Hebrew calendar processing requirements
|
||||
3. **Excellent Performance**: Efficient algorithm implementation and optimized memory usage
|
||||
4. **Reliable Quality**: 100% test coverage and authority verification
|
||||
5. **Easy to Use**: Clean API design and complete documentation
|
||||
|
||||
This module provides a reliable technical foundation for Hebrew calendar processing, suitable for religious, cultural, educational, technical, and other application scenarios, and is an important component of the Carbon date and time library.
|
||||
61
vendor/github.com/dromara/carbon/v2/calendar/julian/README.cn.md
generated
vendored
61
vendor/github.com/dromara/carbon/v2/calendar/julian/README.cn.md
generated
vendored
@@ -1,61 +0,0 @@
|
||||
# 儒略日/简化儒略日
|
||||
|
||||
简体中文 | [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
|
||||
```
|
||||
|
||||
|
||||
60
vendor/github.com/dromara/carbon/v2/calendar/julian/README.jp.md
generated
vendored
60
vendor/github.com/dromara/carbon/v2/calendar/julian/README.jp.md
generated
vendored
@@ -1,60 +0,0 @@
|
||||
# 儒略の日/簡略儒略の日
|
||||
|
||||
日本語 | [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
|
||||
```
|
||||
60
vendor/github.com/dromara/carbon/v2/calendar/julian/README.md
generated
vendored
60
vendor/github.com/dromara/carbon/v2/calendar/julian/README.md
generated
vendored
@@ -1,60 +0,0 @@
|
||||
# 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
|
||||
```
|
||||
3
vendor/github.com/dromara/carbon/v2/calendar/julian/julian.go
generated
vendored
3
vendor/github.com/dromara/carbon/v2/calendar/julian/julian.go
generated
vendored
@@ -56,7 +56,8 @@ func FromStdTime(t time.Time) *Julian {
|
||||
d := float64(t.Day()) + ((float64(t.Second())/60+float64(t.Minute()))/60+float64(t.Hour()))/24
|
||||
n := 0
|
||||
f := false
|
||||
if y*372+m*31+int(d) >= 588829 {
|
||||
// Check if date is on or after Gregorian reform (October 15, 1582)
|
||||
if (y > 1582) || (y == 1582 && m > 10) || (y == 1582 && m == 10 && int(d) >= 15) {
|
||||
f = true
|
||||
}
|
||||
if m <= 2 {
|
||||
|
||||
1901
vendor/github.com/dromara/carbon/v2/calendar/julian/julian_test_data.json
generated
vendored
Normal file
1901
vendor/github.com/dromara/carbon/v2/calendar/julian/julian_test_data.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
188
vendor/github.com/dromara/carbon/v2/calendar/julian/test_report.cn.md
generated
vendored
Normal file
188
vendor/github.com/dromara/carbon/v2/calendar/julian/test_report.cn.md
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
# 儒略历(Julian Calendar)测试报告
|
||||
|
||||
## 概述
|
||||
|
||||
本报告详细记录了 `calendar/julian` 包的测试情况,包括功能测试、性能基准测试和权威数据验证。儒略历实现提供了完整的儒略日(Julian Day Number)计算和日期转换功能。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
- **儒略日计算**:支持儒略日(JD)和修正儒略日(MJD)的计算
|
||||
- **日期转换**:儒略历与格里历之间的双向转换
|
||||
- **时区支持**:支持指定时区的日期转换
|
||||
- **精度控制**:可配置的小数位数精度
|
||||
- **边界处理**:正确处理格里历改革边界(1582年10月15日)
|
||||
|
||||
### 主要方法
|
||||
- `NewJulian(f float64)` - 创建儒略历实例
|
||||
- `FromStdTime(t time.Time)` - 从标准时间创建儒略历实例
|
||||
- `ToGregorian(timezone ...string)` - 转换为格里历
|
||||
- `JD(precision ...int)` - 获取儒略日
|
||||
- `MJD(precision ...int)` - 获取修正儒略日
|
||||
|
||||
## 测试覆盖情况
|
||||
|
||||
### 代码覆盖率
|
||||
- **语句覆盖率**:100.0%
|
||||
- **分支覆盖率**:完整覆盖
|
||||
- **函数覆盖率**:100%
|
||||
|
||||
### 测试用例统计
|
||||
- **单元测试**:5个主要测试函数
|
||||
- **子测试**:15个子测试用例
|
||||
- **权威数据测试**:211个测试用例
|
||||
- **基准测试**:13个性能测试
|
||||
|
||||
## 单元测试详情
|
||||
|
||||
### 1. TestFromStdTime
|
||||
测试从标准时间创建儒略历实例的功能。
|
||||
|
||||
**测试场景:**
|
||||
- 零时间处理:验证空时间返回默认值
|
||||
- 有效时间:验证正常日期转换
|
||||
|
||||
**测试结果:** ✅ 通过
|
||||
|
||||
### 2. TestJulian_ToGregorian
|
||||
测试儒略历到格里历的转换功能。
|
||||
|
||||
**测试场景:**
|
||||
- 零儒略历:验证默认值处理
|
||||
- 空指针:验证nil指针处理
|
||||
- 无效时区:验证时区错误处理
|
||||
- 无时区:验证UTC时区转换
|
||||
- 指定时区:验证自定义时区转换
|
||||
|
||||
**测试结果:** ✅ 通过
|
||||
|
||||
### 3. TestJulian_JD
|
||||
测试儒略日获取功能。
|
||||
|
||||
**测试场景:**
|
||||
- 空指针:验证nil指针处理
|
||||
- 零值:验证零值处理
|
||||
- 有效时间:验证不同精度的儒略日计算
|
||||
|
||||
**测试结果:** ✅ 通过
|
||||
|
||||
### 4. TestJulian_MJD
|
||||
测试修正儒略日获取功能。
|
||||
|
||||
**测试场景:**
|
||||
- 空指针:验证nil指针处理
|
||||
- 零值:验证零值处理
|
||||
- 有效时间:验证不同精度的修正儒略日计算
|
||||
|
||||
**测试结果:** ✅ 通过
|
||||
|
||||
### 5. TestJulian_AuthorityData
|
||||
基于权威数据的综合验证测试。
|
||||
|
||||
**测试数据:**
|
||||
- **测试用例数量**:211个
|
||||
- **数据来源**:基于Go兼容算法生成的权威数据
|
||||
- **覆盖范围**:
|
||||
- 重要历史日期(儒略历改革、JDN纪元等)
|
||||
- 年份边界(2020-2024年)
|
||||
- 闰年测试(2020年、2024年2月29日)
|
||||
- 月份边界(每月第一天和最后一天)
|
||||
- 历史日期(1000年、1500年、1600年、1700年、1800年、1900年)
|
||||
|
||||
**测试内容:**
|
||||
- 儒略历到格里历转换验证
|
||||
- 格里历到儒略历转换验证
|
||||
- 双向转换一致性验证
|
||||
|
||||
**测试结果:** ✅ 通过
|
||||
|
||||
## 性能基准测试
|
||||
|
||||
### 测试环境
|
||||
- **操作系统**:macOS (darwin)
|
||||
- **架构**:ARM64
|
||||
- **CPU**:Apple M1
|
||||
- **Go版本**:最新稳定版
|
||||
|
||||
### 性能测试结果
|
||||
|
||||
| 测试名称 | 操作次数 | 平均耗时 | 内存分配 | 分配次数 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| NewJulian | 34,319,298 | 34.08 ns/op | 24 B/op | 2 allocs/op |
|
||||
| FromStdTime | 16,629,462 | 71.87 ns/op | 37 B/op | 2 allocs/op |
|
||||
| ToGregorian | 25,993,741 | 47.34 ns/op | 48 B/op | 1 allocs/op |
|
||||
| ToGregorianWithTimezone | 22,839 | 51,826 ns/op | 4,672 B/op | 11 allocs/op |
|
||||
| JD | 395,066,280 | 3.024 ns/op | 0 B/op | 0 allocs/op |
|
||||
| MJD | 396,402,154 | 3.119 ns/op | 0 B/op | 0 allocs/op |
|
||||
| ParseFloat64 | 466,306,594 | 2.568 ns/op | 0 B/op | 0 allocs/op |
|
||||
|
||||
### 特殊场景性能测试
|
||||
|
||||
| 测试场景 | 操作次数 | 平均耗时 | 内存分配 | 分配次数 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| JulianDayCalculation | 14,732,007 | 82.02 ns/op | 37 B/op | 2 allocs/op |
|
||||
| GregorianReformBoundary | 14,086,711 | 84.80 ns/op | 40 B/op | 3 allocs/op |
|
||||
| LeapYearDates | 15,760,975 | 74.28 ns/op | 40 B/op | 3 allocs/op |
|
||||
| ExtremeDates | 18,734,301 | 68.76 ns/op | 35 B/op | 2 allocs/op |
|
||||
| TimeWithFractionalSeconds | 15,849,063 | 75.79 ns/op | 40 B/op | 3 allocs/op |
|
||||
|
||||
### 性能分析
|
||||
|
||||
1. **基础操作性能**
|
||||
- 儒略日获取(JD/MJD):约3ns,无内存分配
|
||||
- 浮点数解析:约2.6ns,无内存分配
|
||||
- 新实例创建:约34ns,24字节内存分配
|
||||
|
||||
2. **日期转换性能**
|
||||
- 标准时间转换:约72ns,37字节内存分配
|
||||
- 格里历转换:约47ns,48字节内存分配
|
||||
- 带时区转换:约52μs,4.7KB内存分配(时区加载开销)
|
||||
|
||||
3. **特殊场景性能**
|
||||
- 格里历改革边界:约85ns,性能稳定
|
||||
- 闰年处理:约74ns,性能良好
|
||||
- 极端日期:约69ns,性能稳定
|
||||
- 小数秒处理:约76ns,性能良好
|
||||
|
||||
## 算法验证
|
||||
|
||||
### 权威数据验证
|
||||
- **验证方法**:使用Go兼容算法生成的211个测试用例
|
||||
- **验证范围**:涵盖历史日期、边界条件、闰年等关键场景
|
||||
- **验证结果**:所有测试用例通过,算法正确性得到确认
|
||||
|
||||
### 关键算法特性
|
||||
1. **格里历改革处理**:正确处理1582年10月15日的历法改革
|
||||
2. **闰年计算**:基于儒略历规则的闰年判断
|
||||
3. **精度控制**:支持可配置的小数位数精度
|
||||
4. **时区转换**:支持全球时区的日期转换
|
||||
|
||||
## 质量评估
|
||||
|
||||
### 代码质量
|
||||
- **代码覆盖率**:100%语句覆盖
|
||||
- **错误处理**:完整的nil指针和边界条件处理
|
||||
- **内存管理**:合理的内存分配策略
|
||||
- **性能优化**:高效的算法实现
|
||||
|
||||
### 功能完整性
|
||||
- **核心功能**:完整的儒略历计算功能
|
||||
- **边界处理**:正确处理各种边界情况
|
||||
- **时区支持**:全球时区支持
|
||||
- **精度控制**:灵活的精度配置
|
||||
|
||||
### 可靠性
|
||||
- **权威验证**:通过211个权威数据测试
|
||||
- **性能稳定**:在各种场景下性能表现稳定
|
||||
- **错误处理**:完善的错误处理机制
|
||||
|
||||
## 总结
|
||||
|
||||
儒略历实现通过了全面的测试验证,具备以下特点:
|
||||
|
||||
1. **功能完整**:提供完整的儒略历计算和转换功能
|
||||
2. **性能优异**:基础操作在纳秒级别,复杂操作在微秒级别
|
||||
3. **质量可靠**:100%代码覆盖率,通过权威数据验证
|
||||
4. **易于使用**:简洁的API设计,支持多种使用场景
|
||||
|
||||
该实现可以安全地用于生产环境,为应用程序提供可靠的儒略历计算服务。
|
||||
220
vendor/github.com/dromara/carbon/v2/calendar/julian/test_report.en.md
generated
vendored
Normal file
220
vendor/github.com/dromara/carbon/v2/calendar/julian/test_report.en.md
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
# Julian Calendar Test Report
|
||||
|
||||
## Overview
|
||||
|
||||
This report provides a comprehensive analysis of the `calendar/julian` package testing, including functional tests, performance benchmarks, and authoritative data validation. The Julian calendar implementation offers complete Julian Day Number (JDN) calculation and date conversion capabilities.
|
||||
|
||||
## Features
|
||||
|
||||
### Core Functionality
|
||||
- **Julian Day Calculation**: Support for Julian Day (JD) and Modified Julian Day (MJD) calculations
|
||||
- **Date Conversion**: Bidirectional conversion between Julian and Gregorian calendars
|
||||
- **Timezone Support**: Date conversion with specified timezones
|
||||
- **Precision Control**: Configurable decimal precision
|
||||
- **Boundary Handling**: Proper handling of Gregorian reform boundary (October 15, 1582)
|
||||
|
||||
### Main Methods
|
||||
- `NewJulian(f float64)` - Create a Julian calendar instance
|
||||
- `FromStdTime(t time.Time)` - Create Julian instance from standard time
|
||||
- `ToGregorian(timezone ...string)` - Convert to Gregorian calendar
|
||||
- `JD(precision ...int)` - Get Julian Day
|
||||
- `MJD(precision ...int)` - Get Modified Julian Day
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Code Coverage
|
||||
- **Statement Coverage**: 100.0%
|
||||
- **Branch Coverage**: Complete coverage
|
||||
- **Function Coverage**: 100%
|
||||
|
||||
### Test Case Statistics
|
||||
- **Unit Tests**: 5 main test functions
|
||||
- **Sub-tests**: 15 sub-test cases
|
||||
- **Authority Data Tests**: 211 test cases
|
||||
- **Benchmark Tests**: 13 performance tests
|
||||
|
||||
## Unit Test Details
|
||||
|
||||
### 1. TestFromStdTime
|
||||
Tests the functionality of creating Julian calendar instances from standard time.
|
||||
|
||||
**Test Scenarios:**
|
||||
- Zero time handling: Verify default values for empty time
|
||||
- Valid time: Verify normal date conversion
|
||||
|
||||
**Test Result:** ✅ Passed
|
||||
|
||||
### 2. TestJulian_ToGregorian
|
||||
Tests Julian to Gregorian calendar conversion functionality.
|
||||
|
||||
**Test Scenarios:**
|
||||
- Zero Julian: Verify default value handling
|
||||
- Nil pointer: Verify nil pointer handling
|
||||
- Invalid timezone: Verify timezone error handling
|
||||
- No timezone: Verify UTC timezone conversion
|
||||
- Specified timezone: Verify custom timezone conversion
|
||||
|
||||
**Test Result:** ✅ Passed
|
||||
|
||||
### 3. TestJulian_JD
|
||||
Tests Julian Day retrieval functionality.
|
||||
|
||||
**Test Scenarios:**
|
||||
- Nil pointer: Verify nil pointer handling
|
||||
- Zero value: Verify zero value handling
|
||||
- Valid time: Verify Julian Day calculation with different precisions
|
||||
|
||||
**Test Result:** ✅ Passed
|
||||
|
||||
### 4. TestJulian_MJD
|
||||
Tests Modified Julian Day retrieval functionality.
|
||||
|
||||
**Test Scenarios:**
|
||||
- Nil pointer: Verify nil pointer handling
|
||||
- Zero value: Verify zero value handling
|
||||
- Valid time: Verify Modified Julian Day calculation with different precisions
|
||||
|
||||
**Test Result:** ✅ Passed
|
||||
|
||||
### 5. TestJulian_AuthorityData
|
||||
Comprehensive validation test based on authoritative data.
|
||||
|
||||
**Test Data:**
|
||||
- **Number of Test Cases**: 211
|
||||
- **Data Source**: Authoritative data generated using Go-compatible algorithm
|
||||
- **Coverage Scope**:
|
||||
- Important historical dates (Julian calendar reform, JDN epoch, etc.)
|
||||
- Year boundaries (2020-2024)
|
||||
- Leap year tests (February 29, 2020 and 2024)
|
||||
- Month boundaries (first and last day of each month)
|
||||
- Historical dates (1000, 1500, 1600, 1700, 1800, 1900)
|
||||
|
||||
**Test Content:**
|
||||
- Julian to Gregorian conversion validation
|
||||
- Gregorian to Julian conversion validation
|
||||
- Bidirectional conversion consistency verification
|
||||
|
||||
**Test Result:** ✅ Passed
|
||||
|
||||
## Performance Benchmark Tests
|
||||
|
||||
### Test Environment
|
||||
- **Operating System**: macOS (darwin)
|
||||
- **Architecture**: ARM64
|
||||
- **CPU**: Apple M1
|
||||
- **Go Version**: Latest stable release
|
||||
|
||||
### Performance Test Results
|
||||
|
||||
| Test Name | Operations | Average Time | Memory Allocation | Allocations |
|
||||
|-----------|------------|--------------|-------------------|-------------|
|
||||
| NewJulian | 34,319,298 | 34.08 ns/op | 24 B/op | 2 allocs/op |
|
||||
| FromStdTime | 16,629,462 | 71.87 ns/op | 37 B/op | 2 allocs/op |
|
||||
| ToGregorian | 25,993,741 | 47.34 ns/op | 48 B/op | 1 allocs/op |
|
||||
| ToGregorianWithTimezone | 22,839 | 51,826 ns/op | 4,672 B/op | 11 allocs/op |
|
||||
| JD | 395,066,280 | 3.024 ns/op | 0 B/op | 0 allocs/op |
|
||||
| MJD | 396,402,154 | 3.119 ns/op | 0 B/op | 0 allocs/op |
|
||||
| ParseFloat64 | 466,306,594 | 2.568 ns/op | 0 B/op | 0 allocs/op |
|
||||
|
||||
### Special Scenario Performance Tests
|
||||
|
||||
| Test Scenario | Operations | Average Time | Memory Allocation | Allocations |
|
||||
|---------------|------------|--------------|-------------------|-------------|
|
||||
| JulianDayCalculation | 14,732,007 | 82.02 ns/op | 37 B/op | 2 allocs/op |
|
||||
| GregorianReformBoundary | 14,086,711 | 84.80 ns/op | 40 B/op | 3 allocs/op |
|
||||
| LeapYearDates | 15,760,975 | 74.28 ns/op | 40 B/op | 3 allocs/op |
|
||||
| ExtremeDates | 18,734,301 | 68.76 ns/op | 35 B/op | 2 allocs/op |
|
||||
| TimeWithFractionalSeconds | 15,849,063 | 75.79 ns/op | 40 B/op | 3 allocs/op |
|
||||
|
||||
### Performance Analysis
|
||||
|
||||
1. **Basic Operation Performance**
|
||||
- Julian Day retrieval (JD/MJD): ~3ns, no memory allocation
|
||||
- Float parsing: ~2.6ns, no memory allocation
|
||||
- New instance creation: ~34ns, 24 bytes memory allocation
|
||||
|
||||
2. **Date Conversion Performance**
|
||||
- Standard time conversion: ~72ns, 37 bytes memory allocation
|
||||
- Gregorian conversion: ~47ns, 48 bytes memory allocation
|
||||
- Timezone conversion: ~52μs, 4.7KB memory allocation (timezone loading overhead)
|
||||
|
||||
3. **Special Scenario Performance**
|
||||
- Gregorian reform boundary: ~85ns, stable performance
|
||||
- Leap year handling: ~74ns, good performance
|
||||
- Extreme dates: ~69ns, stable performance
|
||||
- Fractional seconds: ~76ns, good performance
|
||||
|
||||
## Algorithm Validation
|
||||
|
||||
### Authority Data Validation
|
||||
- **Validation Method**: 211 test cases generated using Go-compatible algorithm
|
||||
- **Validation Scope**: Covers historical dates, boundary conditions, leap years, and other critical scenarios
|
||||
- **Validation Result**: All test cases passed, confirming algorithm correctness
|
||||
|
||||
### Key Algorithm Features
|
||||
1. **Gregorian Reform Handling**: Proper handling of the calendar reform on October 15, 1582
|
||||
2. **Leap Year Calculation**: Leap year determination based on Julian calendar rules
|
||||
3. **Precision Control**: Support for configurable decimal precision
|
||||
4. **Timezone Conversion**: Support for global timezone date conversion
|
||||
|
||||
## Quality Assessment
|
||||
|
||||
### Code Quality
|
||||
- **Code Coverage**: 100% statement coverage
|
||||
- **Error Handling**: Complete nil pointer and boundary condition handling
|
||||
- **Memory Management**: Reasonable memory allocation strategy
|
||||
- **Performance Optimization**: Efficient algorithm implementation
|
||||
|
||||
### Functional Completeness
|
||||
- **Core Functions**: Complete Julian calendar calculation functionality
|
||||
- **Boundary Handling**: Proper handling of various boundary conditions
|
||||
- **Timezone Support**: Global timezone support
|
||||
- **Precision Control**: Flexible precision configuration
|
||||
|
||||
### Reliability
|
||||
- **Authority Validation**: Passed 211 authoritative data tests
|
||||
- **Performance Stability**: Stable performance across various scenarios
|
||||
- **Error Handling**: Comprehensive error handling mechanism
|
||||
|
||||
## Key Findings
|
||||
|
||||
### Strengths
|
||||
1. **Complete Functionality**: Provides comprehensive Julian calendar calculation and conversion capabilities
|
||||
2. **Excellent Performance**: Basic operations at nanosecond level, complex operations at microsecond level
|
||||
3. **High Reliability**: 100% code coverage with authoritative data validation
|
||||
4. **Easy to Use**: Clean API design supporting multiple usage scenarios
|
||||
|
||||
### Performance Highlights
|
||||
- **Fastest Operations**: JD/MJD retrieval (~3ns) and float parsing (~2.6ns)
|
||||
- **Efficient Conversions**: Standard date conversions under 100ns
|
||||
- **Memory Efficient**: Most operations require minimal memory allocation
|
||||
- **Scalable**: Performance remains stable across different date ranges
|
||||
|
||||
### Quality Metrics
|
||||
- **Test Coverage**: 100% statement coverage achieved
|
||||
- **Test Cases**: 211 comprehensive test cases covering edge cases
|
||||
- **Performance**: All operations perform within acceptable ranges
|
||||
- **Reliability**: Zero test failures across all scenarios
|
||||
|
||||
## Recommendations
|
||||
|
||||
### For Production Use
|
||||
1. **Ready for Production**: The implementation is production-ready with comprehensive testing
|
||||
2. **Performance Monitoring**: Monitor timezone conversion performance in high-frequency scenarios
|
||||
3. **Memory Usage**: Consider memory allocation patterns for high-throughput applications
|
||||
|
||||
### For Future Development
|
||||
1. **Extend Test Coverage**: Consider adding more edge cases for extreme historical dates
|
||||
2. **Performance Optimization**: Further optimize timezone conversion for better performance
|
||||
3. **Documentation**: Maintain comprehensive documentation for API usage
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Julian calendar implementation has passed comprehensive testing and validation, demonstrating:
|
||||
|
||||
1. **Functional Completeness**: Complete Julian calendar calculation and conversion functionality
|
||||
2. **Superior Performance**: Basic operations at nanosecond level, complex operations at microsecond level
|
||||
3. **Reliable Quality**: 100% code coverage with authoritative data validation
|
||||
4. **User-Friendly**: Clean API design supporting multiple usage scenarios
|
||||
|
||||
This implementation can be safely deployed in production environments, providing reliable Julian calendar calculation services for applications.
|
||||
98
vendor/github.com/dromara/carbon/v2/calendar/lunar/README.cn.md
generated
vendored
98
vendor/github.com/dromara/carbon/v2/calendar/lunar/README.cn.md
generated
vendored
@@ -1,98 +0,0 @@
|
||||
# 中国农历
|
||||
|
||||
简体中文 | [English](README.md) | [日本語](README.jp.md)
|
||||
|
||||
#### 用法示例
|
||||
|
||||
> 目前仅支持公元 `1900` 年至 `2100` 年的 `200` 年时间跨度
|
||||
|
||||
##### 将 `公历` 转换成 `农历`
|
||||
|
||||
```go
|
||||
// 获取农历生肖
|
||||
carbon.Parse("2020-08-05").Lunar().Animal() // 鼠
|
||||
// 获取农历节日
|
||||
carbon.Parse("2021-02-12").Lunar().Festival() // 春节
|
||||
|
||||
// 获取农历年份
|
||||
carbon.Parse("2020-08-05").Lunar().Year() // 2020
|
||||
// 获取农历月份
|
||||
carbon.Parse("2020-08-05").Lunar().Month() // 6
|
||||
// 获取农历闰月月份
|
||||
carbon.Parse("2020-08-05").Lunar().LeapMonth() // 4
|
||||
// 获取农历日期
|
||||
carbon.Parse("2020-08-05").Lunar().Day() // 16
|
||||
// 获取农历时辰
|
||||
carbon.Parse("2020-08-05").Lunar().Hour() // 13
|
||||
// 获取农历分钟
|
||||
carbon.Parse("2020-08-05").Lunar().Minute() // 14
|
||||
// 获取农历秒数
|
||||
carbon.Parse("2020-08-05").Lunar().Second() // 15
|
||||
|
||||
// 获取农历日期时间字符串
|
||||
carbon.Parse("2020-08-05").Lunar().String() // 2020-06-16
|
||||
fmt.Printf("%s", carbon.Parse("2020-08-05").Lunar()) // 2020-06-16
|
||||
// 获取农历年字符串
|
||||
carbon.Parse("2020-08-05").Lunar().ToYearString() // 二零二零
|
||||
// 获取农历月字符串
|
||||
carbon.Parse("2020-08-05").Lunar().ToMonthString() // 六月
|
||||
// 获取农历闰月字符串
|
||||
carbon.Parse("2020-04-23").Lunar().ToMonthString() // 闰四月
|
||||
// 获取农历周字符串
|
||||
carbon.Parse("2020-04-23").Lunar().ToWeekString() // 周四
|
||||
// 获取农历天字符串
|
||||
carbon.Parse("2020-08-05").Lunar().ToDayString() // 十六
|
||||
// 获取农历日期字符串
|
||||
carbon.Parse("2020-08-05").Lunar().ToDateString() // 二零二零年六月十六
|
||||
|
||||
```
|
||||
|
||||
##### 将 `农历` 转化成 `公历`
|
||||
|
||||
```go
|
||||
// 将农历 二零二三年腊月十一 转化为 公历
|
||||
carbon.CreateFromLunar(2023, 12, 11, false).ToDateTimeString() // 2024-01-21 00:00:00
|
||||
// 将农历 二零二三年二月十一 转化为 公历
|
||||
carbon.CreateFromLunar(2023, 2, 11, false).ToDateTimeString() // 2023-03-02 00:00:00
|
||||
// 将农历 二零二三年闰二月十一 转化为 公历
|
||||
carbon.CreateFromLunar(2023, 2, 11, true).ToDateTimeString() // 2023-04-01 00:00:00
|
||||
```
|
||||
|
||||
##### 日期判断
|
||||
|
||||
```go
|
||||
|
||||
// 是否是合法农历日期
|
||||
carbon.Parse("0000-00-00").Lunar().IsValid() // false
|
||||
carbon.Parse("2020-08-05").Lunar().IsValid() // true
|
||||
|
||||
// 是否是农历闰年
|
||||
carbon.Parse("2020-08-05").Lunar().IsLeapYear() // true
|
||||
// 是否是农历闰月
|
||||
carbon.Parse("2020-08-05").Lunar().IsLeapMonth() // false
|
||||
|
||||
// 是否是鼠年
|
||||
carbon.Parse("2020-08-05").Lunar().IsRatYear() // true
|
||||
// 是否是牛年
|
||||
carbon.Parse("2020-08-05").Lunar().IsOxYear() // false
|
||||
// 是否是虎年
|
||||
carbon.Parse("2020-08-05").Lunar().IsTigerYear() // false
|
||||
// 是否是兔年
|
||||
carbon.Parse("2020-08-05").Lunar().IsRabbitYear() // false
|
||||
// 是否是龙年
|
||||
carbon.Parse("2020-08-05").Lunar().IsDragonYear() // false
|
||||
// 是否是蛇年
|
||||
carbon.Parse("2020-08-05").Lunar().IsSnakeYear() // false
|
||||
// 是否是马年
|
||||
carbon.Parse("2020-08-05").Lunar().IsHorseYear() // false
|
||||
// 是否是羊年
|
||||
carbon.Parse("2020-08-05").Lunar().IsGoatYear() // false
|
||||
// 是否是猴年
|
||||
carbon.Parse("2020-08-05").Lunar().IsMonkeyYear() // false
|
||||
// 是否是鸡年
|
||||
carbon.Parse("2020-08-05").Lunar().IsRoosterYear() // false
|
||||
// 是否是狗年
|
||||
carbon.Parse("2020-08-05").Lunar().IsDogYear() // false
|
||||
// 是否是猪年
|
||||
carbon.Parse("2020-08-05").Lunar().IsPigYear() // false
|
||||
```
|
||||
97
vendor/github.com/dromara/carbon/v2/calendar/lunar/README.jp.md
generated
vendored
97
vendor/github.com/dromara/carbon/v2/calendar/lunar/README.jp.md
generated
vendored
@@ -1,97 +0,0 @@
|
||||
# 中国の旧暦
|
||||
|
||||
日本語 | [English](README.md) | [简体中文](README.cn.md)
|
||||
|
||||
#### 使い方の例
|
||||
|
||||
> 現在は西暦` 1900 `年から` 2100 `年までの` 200 `年の時間スパンのみをサポートしている
|
||||
|
||||
##### `西暦`を`旧暦`に変換する
|
||||
|
||||
```go
|
||||
// 旧暦の干支を手に入れる
|
||||
carbon.Parse("2020-08-05").Lunar().Animal() // 鼠
|
||||
// 旧暦の祝日を取得する
|
||||
carbon.Parse("2021-02-12").Lunar().Festival() // 春节
|
||||
|
||||
// 旧正月の取得
|
||||
carbon.Parse("2020-08-05").Lunar().Year() // 2020
|
||||
// 旧暦月の取得
|
||||
carbon.Parse("2020-08-05").Lunar().Month() // 6
|
||||
// 旧暦うるう月の取得
|
||||
carbon.Parse("2020-08-05").Lunar().LeapMonth() // 4
|
||||
// 旧暦日の取得
|
||||
carbon.Parse("2020-08-05").Lunar().Day() // 16
|
||||
// 旧暦時刻の取得
|
||||
carbon.Parse("2020-08-05").Lunar().Hour() // 13
|
||||
// 旧暦分の取得
|
||||
carbon.Parse("2020-08-05").Lunar().Minute() // 14
|
||||
// 旧暦の取得秒数
|
||||
carbon.Parse("2020-08-05").Lunar().Second() // 15
|
||||
|
||||
// 旧暦日時文字列の取得
|
||||
carbon.Parse("2020-08-05").Lunar().String() // 2020-06-16
|
||||
fmt.Printf("%s", carbon.Parse("2020-08-05").Lunar()) // 2020-06-16
|
||||
// 旧正月文字列の取得
|
||||
carbon.Parse("2020-08-05").Lunar().ToYearString() // 二零二零
|
||||
// 旧暦月文字列の取得
|
||||
carbon.Parse("2020-08-05").Lunar().ToMonthString() // 六月
|
||||
// 旧暦うるう月文字列の取得
|
||||
carbon.Parse("2020-04-23").Lunar().ToMonthString() // 闰四月
|
||||
// 旧暦週文字列の取得
|
||||
carbon.Parse("2020-04-23").Lunar().ToWeekString() // 周四
|
||||
// 旧暦日文字列の取得
|
||||
carbon.Parse("2020-08-05").Lunar().ToDayString() // 十六
|
||||
// 旧暦日付文字列の取得
|
||||
carbon.Parse("2020-08-05").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").Lunar().IsValid() // false
|
||||
carbon.Parse("2020-08-05").Lunar().IsValid() // true
|
||||
|
||||
// 旧暦うるう年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsLeapYear() // true
|
||||
// 旧暦うるう月かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsLeapMonth() // false
|
||||
|
||||
// ねずみ年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsRatYear() // true
|
||||
// 牛年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsOxYear() // false
|
||||
// 寅年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsTigerYear() // false
|
||||
// うさぎ年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsRabbitYear() // false
|
||||
// 龍年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsDragonYear() // false
|
||||
// 蛇の年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsSnakeYear() // false
|
||||
// 馬年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsHorseYear() // false
|
||||
// 羊年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsGoatYear() // false
|
||||
// 申年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsMonkeyYear() // false
|
||||
// 鶏の年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsRoosterYear() // false
|
||||
// 犬年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsDogYear() // false
|
||||
// 豚年かどうか
|
||||
carbon.Parse("2020-08-05").Lunar().IsPigYear() // false
|
||||
|
||||
```
|
||||
97
vendor/github.com/dromara/carbon/v2/calendar/lunar/README.md
generated
vendored
97
vendor/github.com/dromara/carbon/v2/calendar/lunar/README.md
generated
vendored
@@ -1,97 +0,0 @@
|
||||
# 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").Lunar().Festival() // 春节
|
||||
|
||||
// Get lunar year
|
||||
carbon.Parse("2020-08-05").Lunar().Year() // 2020
|
||||
// Get lunar month
|
||||
carbon.Parse("2020-08-05").Lunar().Month() // 6
|
||||
// Get lunar leap month
|
||||
carbon.Parse("2020-08-05").Lunar().LeapMonth() // 4
|
||||
// Get lunar day
|
||||
carbon.Parse("2020-08-05").Lunar().Day() // 16
|
||||
// Get lunar hour
|
||||
carbon.Parse("2020-08-05").Lunar().Hour() // 13
|
||||
// Get lunar minute
|
||||
carbon.Parse("2020-08-05").Lunar().Minute() // 14
|
||||
// Get lunar second
|
||||
carbon.Parse("2020-08-05").Lunar().Second() // 15
|
||||
|
||||
// Get lunar date and time string
|
||||
carbon.Parse("2020-08-05").Lunar().String() // 2020-06-16
|
||||
fmt.Printf("%s", carbon.Parse("2020-08-05").Lunar()) // 2020-06-16
|
||||
// Get lunar year as string
|
||||
carbon.Parse("2020-08-05").Lunar().ToYearString() // 二零二零
|
||||
// Get lunar month as string
|
||||
carbon.Parse("2020-08-05").Lunar().ToMonthString() // 六月
|
||||
// Get lunar leap month as string
|
||||
carbon.Parse("2020-04-23").Lunar().ToMonthString() // 闰四月
|
||||
// Get lunar week as string
|
||||
carbon.Parse("2020-04-23").Lunar().ToWeekString() // 周四
|
||||
// Get lunar day as string
|
||||
carbon.Parse("2020-08-05").Lunar().ToDayString() // 十六
|
||||
// Get lunar date as string
|
||||
carbon.Parse("2020-08-05").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").Lunar().IsValid() // false
|
||||
carbon.Parse("2020-08-05").Lunar().IsValid() // true
|
||||
|
||||
// Whether is a lunar leap year
|
||||
carbon.Parse("2020-08-05").Lunar().IsLeapYear() // true
|
||||
// Whether is a lunar leap month
|
||||
carbon.Parse("2020-08-05").Lunar().IsLeapMonth() // false
|
||||
|
||||
// Whether is a lunar year of the rat
|
||||
carbon.Parse("2020-08-05").Lunar().IsRatYear() // true
|
||||
// Whether is a lunar year of the ox
|
||||
carbon.Parse("2020-08-05").Lunar().IsOxYear() // false
|
||||
// Whether is a lunar year of the tiger
|
||||
carbon.Parse("2020-08-05").Lunar().IsTigerYear() // false
|
||||
// Whether is a lunar year of the rabbit
|
||||
carbon.Parse("2020-08-05").Lunar().IsRabbitYear() // false
|
||||
// Whether is a lunar year of the dragon
|
||||
carbon.Parse("2020-08-05").Lunar().IsDragonYear() // false
|
||||
// Whether is a lunar year of the snake
|
||||
carbon.Parse("2020-08-05").Lunar().IsSnakeYear() // false
|
||||
// Whether is a lunar year of the horse
|
||||
carbon.Parse("2020-08-05").Lunar().IsHorseYear() // false
|
||||
// Whether is a lunar year of the goat
|
||||
carbon.Parse("2020-08-05").Lunar().IsGoatYear() // false
|
||||
// Whether is a lunar year of the monkey
|
||||
carbon.Parse("2020-08-05").Lunar().IsMonkeyYear() // false
|
||||
// Whether is a lunar year of the rooster
|
||||
carbon.Parse("2020-08-05").Lunar().IsRoosterYear() // false
|
||||
// Whether is a lunar year of the dog
|
||||
carbon.Parse("2020-08-05").Lunar().IsDogYear() // false
|
||||
// Whether is a lunar year of the dig
|
||||
carbon.Parse("2020-08-05").Lunar().IsPigYear() // false
|
||||
|
||||
```
|
||||
123
vendor/github.com/dromara/carbon/v2/calendar/lunar/lunar.go
generated
vendored
123
vendor/github.com/dromara/carbon/v2/calendar/lunar/lunar.go
generated
vendored
@@ -54,12 +54,10 @@ var (
|
||||
0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252, // 2090-2099
|
||||
0x0d520, // 2100
|
||||
}
|
||||
)
|
||||
|
||||
// ErrInvalidLunar returns a invalid lunar date.
|
||||
var ErrInvalidLunar = func() error {
|
||||
return fmt.Errorf("invalid lunar date, please make sure the lunar date is valid")
|
||||
}
|
||||
maxYear = 2100
|
||||
minYear = 1900
|
||||
)
|
||||
|
||||
// Lunar defines a Lunar struct.
|
||||
type Lunar struct {
|
||||
@@ -73,29 +71,13 @@ func NewLunar(year, month, day int, isLeapMonth bool) *Lunar {
|
||||
l := new(Lunar)
|
||||
l.year, l.month, l.day, l.isLeapMonth = year, month, day, isLeapMonth
|
||||
if !l.IsValid() {
|
||||
l.Error = ErrInvalidLunar()
|
||||
if !l.IsValid() {
|
||||
l.Error = fmt.Errorf("invalid persian date: %04d-%02d-%02d", year, month, day)
|
||||
}
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// MaxValue returns a Lunar instance for the greatest supported date.
|
||||
func MaxValue() *Lunar {
|
||||
return &Lunar{
|
||||
year: 2100,
|
||||
month: 12,
|
||||
day: 31,
|
||||
}
|
||||
}
|
||||
|
||||
// MinValue returns a Lunar instance for the lowest supported date.
|
||||
func MinValue() *Lunar {
|
||||
return &Lunar{
|
||||
year: 1900,
|
||||
month: 1,
|
||||
day: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// FromStdTime creates a Lunar instance from standard time.Time.
|
||||
func FromStdTime(t time.Time) *Lunar {
|
||||
l := new(Lunar)
|
||||
@@ -103,25 +85,24 @@ func FromStdTime(t time.Time) *Lunar {
|
||||
return nil
|
||||
}
|
||||
daysInYear, daysInMonth, leapMonth := 365, 30, 0
|
||||
maxYear, minYear := MaxValue().year, MinValue().year
|
||||
|
||||
offset := int(t.Truncate(time.Hour).Sub(time.Date(minYear, 1, 31, 0, 0, 0, 0, t.Location())).Hours() / 24)
|
||||
for l.year = minYear; l.year <= maxYear && offset > 0; l.year++ {
|
||||
daysInYear = l.getDaysInYear()
|
||||
daysInYear = getDaysInYear(l.year)
|
||||
offset -= daysInYear
|
||||
}
|
||||
if offset < 0 {
|
||||
offset += daysInYear
|
||||
l.year--
|
||||
}
|
||||
leapMonth = l.LeapMonth()
|
||||
leapMonth = getLeapMonth(l.year)
|
||||
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()
|
||||
daysInMonth = getDaysInLeapMonth(l.year)
|
||||
} else {
|
||||
daysInMonth = l.getDaysInMonth()
|
||||
daysInMonth = getDaysInMonth(l.year, l.month)
|
||||
}
|
||||
offset -= daysInMonth
|
||||
if l.isLeapMonth && l.month == (leapMonth+1) {
|
||||
@@ -157,9 +138,9 @@ func (l *Lunar) ToGregorian(timezone ...string) *calendar.Gregorian {
|
||||
if g.Error != nil {
|
||||
return g
|
||||
}
|
||||
days := l.getDaysInMonth()
|
||||
offset := l.getOffsetInYear()
|
||||
offset += l.getOffsetInMonth()
|
||||
days := getDaysInMonth(l.year, l.month)
|
||||
offset := getOffsetInYear(l.year, l.month)
|
||||
offset += getOffsetInMonth(l.year)
|
||||
|
||||
// add the time difference of the month before the leap month
|
||||
if l.isLeapMonth {
|
||||
@@ -216,8 +197,7 @@ func (l *Lunar) LeapMonth() int {
|
||||
if !l.IsValid() {
|
||||
return 0
|
||||
}
|
||||
minYear := MinValue().year
|
||||
return years[l.year-minYear] & 0xf
|
||||
return getLeapMonth(l.year)
|
||||
}
|
||||
|
||||
// String implements "Stringer" interface for Lunar.
|
||||
@@ -234,8 +214,8 @@ func (l *Lunar) ToYearString() (year string) {
|
||||
return ""
|
||||
}
|
||||
year = fmt.Sprintf("%d", l.year)
|
||||
for i := range numbers {
|
||||
year = strings.Replace(year, fmt.Sprintf("%d", i), numbers[i], -1)
|
||||
for k, v := range numbers {
|
||||
year = strings.Replace(year, fmt.Sprintf("%d", k), v, -1)
|
||||
}
|
||||
return year
|
||||
}
|
||||
@@ -293,12 +273,11 @@ func (l *Lunar) ToDateString() string {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
if l.year >= minYear && l.year <= maxYear {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -452,56 +431,80 @@ func (l *Lunar) IsPigYear() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *Lunar) getOffsetInYear() int {
|
||||
// getOffsetInYear calculates the total number of days from the beginning of the year to the specified month.
|
||||
// It handles leap months by adding the leap month days when encountered.
|
||||
// Returns the offset in days.
|
||||
func getOffsetInYear(year, month int) int {
|
||||
flag := false
|
||||
clone, month, offset := *l, 0, 0
|
||||
for month = 1; month < l.month; month++ {
|
||||
leapMonth := l.LeapMonth()
|
||||
offset := 0
|
||||
for m := 1; m < month; m++ {
|
||||
leapMonth := getLeapMonth(year)
|
||||
if !flag {
|
||||
// 处理闰月
|
||||
if leapMonth <= month && leapMonth > 0 {
|
||||
offset += l.getDaysInLeapMonth()
|
||||
if leapMonth <= m && leapMonth > 0 {
|
||||
offset += getDaysInLeapMonth(year)
|
||||
flag = true
|
||||
}
|
||||
}
|
||||
clone.month = month
|
||||
offset += clone.getDaysInMonth()
|
||||
offset += getDaysInMonth(year, m)
|
||||
}
|
||||
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()
|
||||
// getOffsetInMonth calculates the total number of days from the minimum year (1900) to the specified year.
|
||||
// This represents the cumulative days across all years up to but not including the target year.
|
||||
// Returns the offset in days.
|
||||
func getOffsetInMonth(year int) int {
|
||||
offset := 0
|
||||
for y := minYear; y < year; y++ {
|
||||
offset += getDaysInYear(y)
|
||||
}
|
||||
return offset
|
||||
}
|
||||
|
||||
func (l *Lunar) getDaysInYear() int {
|
||||
// getDaysInYear calculates the total number of days in a lunar year.
|
||||
// It uses the lunar calendar data array to determine which months have 30 days vs 29 days.
|
||||
// The base is 348 days (12 months × 29 days), then adds days for months with 30 days.
|
||||
// Finally adds the leap month days if the year has a leap month.
|
||||
// Returns the total number of days in the year.
|
||||
func getDaysInYear(year int) int {
|
||||
var days = 348
|
||||
for i := 0x8000; i > 0x8; i >>= 1 {
|
||||
if (years[l.year-MinValue().year] & i) != 0 {
|
||||
if (years[year-minYear] & i) != 0 {
|
||||
days++
|
||||
}
|
||||
}
|
||||
return days + l.getDaysInLeapMonth()
|
||||
return days + getDaysInLeapMonth(year)
|
||||
}
|
||||
|
||||
func (l *Lunar) getDaysInMonth() int {
|
||||
if (years[l.year-MinValue().year] & (0x10000 >> uint(l.month))) != 0 {
|
||||
// getDaysInMonth calculates the number of days in a specific lunar month.
|
||||
// It uses the lunar calendar data array to determine if the month has 30 or 29 days.
|
||||
// The bit pattern in the data array indicates which months are long (30 days).
|
||||
// Returns 30 for long months, 29 for short months.
|
||||
func getDaysInMonth(year, month int) int {
|
||||
if (years[year-minYear] & (0x10000 >> uint(month))) != 0 {
|
||||
return 30
|
||||
}
|
||||
return 29
|
||||
}
|
||||
|
||||
func (l *Lunar) getDaysInLeapMonth() int {
|
||||
if l.LeapMonth() == 0 {
|
||||
// getDaysInLeapMonth calculates the number of days in the leap month of a lunar year.
|
||||
// If the year has no leap month, returns 0.
|
||||
// If the year has a leap month, determines if it's a long (30 days) or short (29 days) month.
|
||||
// Returns the number of days in the leap month, or 0 if no leap month exists.
|
||||
func getDaysInLeapMonth(year int) int {
|
||||
if getLeapMonth(year) == 0 {
|
||||
return 0
|
||||
}
|
||||
if years[l.year-MinValue().year]&0x10000 != 0 {
|
||||
if years[year-minYear]&0x10000 != 0 {
|
||||
return 30
|
||||
}
|
||||
return 29
|
||||
}
|
||||
|
||||
// getLeapMonth determines which month is the leap month in a lunar year.
|
||||
// Returns 0 if the year has no leap month, or the month number (1-12) if a leap month exists.
|
||||
// The leap month information is stored in the lower 4 bits of the lunar calendar data.
|
||||
// Returns 0 for years outside the supported range (1900-2100).
|
||||
func getLeapMonth(year int) int {
|
||||
return years[year-minYear] & 0xf
|
||||
}
|
||||
|
||||
2312
vendor/github.com/dromara/carbon/v2/calendar/lunar/lunar_test_data.json
generated
vendored
Normal file
2312
vendor/github.com/dromara/carbon/v2/calendar/lunar/lunar_test_data.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
166
vendor/github.com/dromara/carbon/v2/calendar/lunar/test_report.cn.md
generated
vendored
Normal file
166
vendor/github.com/dromara/carbon/v2/calendar/lunar/test_report.cn.md
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
# 农历(Lunar)测试报告
|
||||
|
||||
## 概述
|
||||
|
||||
农历模块是 Carbon 日期时间库的重要组成部分,提供了完整的农历日期处理功能。本报告详细记录了农历模块的功能特性、测试覆盖情况、性能基准和质量评估结果。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
- **农历日期创建与验证**:支持 1900-2100 年范围内的农历日期创建和有效性验证
|
||||
- **格里历转换**:农历日期与格里历日期之间的双向转换
|
||||
- **闰月处理**:完整的闰月计算和验证机制
|
||||
- **时区支持**:支持不同时区的日期转换
|
||||
|
||||
### 格式化功能
|
||||
- **中文数字转换**:年份、月份、日期的中文数字表示
|
||||
- **农历月份表示**:支持闰月标识(如"闰二月")
|
||||
- **完整日期字符串**:生成如"二零二零年正月初一"的完整日期描述
|
||||
- **星期表示**:农历日期的星期信息
|
||||
|
||||
### 生肖与节日
|
||||
- **十二生肖**:基于年份的生肖计算(鼠、牛、虎、兔、龙、蛇、马、羊、猴、鸡、狗、猪)
|
||||
- **传统节日**:支持 12 个主要传统节日的识别
|
||||
- 春节、元宵节、龙抬头、上巳节、端午节
|
||||
- 七夕节、中元节、中秋节、重阳节、寒衣节、下元节、腊八节
|
||||
|
||||
### 验证功能
|
||||
- **年份验证**:支持 1900-2100 年范围验证
|
||||
- **月份验证**:1-12 月范围验证,包含闰月处理
|
||||
- **日期验证**:基于月份天数的日期有效性验证
|
||||
- **生肖年份判断**:12 种生肖年份的快速判断方法
|
||||
|
||||
## 测试覆盖
|
||||
|
||||
### 单元测试统计
|
||||
- **测试用例总数**:544 行测试代码
|
||||
- **代码覆盖率**:100.0% 语句覆盖
|
||||
- **测试通过率**:100% (所有测试用例通过)
|
||||
|
||||
### 测试分类
|
||||
1. **基础功能测试**
|
||||
- 最大/最小值边界测试
|
||||
- 从标准时间创建农历日期
|
||||
- 农历转格里历转换
|
||||
|
||||
2. **格式化功能测试**
|
||||
- 年份、月份、日期字符串转换
|
||||
- 完整日期字符串生成
|
||||
- 星期字符串生成
|
||||
|
||||
3. **生肖与节日测试**
|
||||
- 十二生肖计算验证
|
||||
- 传统节日识别测试
|
||||
|
||||
4. **验证功能测试**
|
||||
- 日期有效性验证
|
||||
- 闰年判断
|
||||
- 闰月判断
|
||||
- 生肖年份判断
|
||||
|
||||
5. **权威数据验证**
|
||||
- 基于 Python 权威库的 165 个测试用例
|
||||
- 涵盖 1900-2100 年的关键日期
|
||||
- 包含传统节日、闰月、边界日期等特殊场景
|
||||
|
||||
### 测试数据规模
|
||||
- **权威测试用例**:165 个
|
||||
- **测试数据文件**:2,311 行 JSON 数据
|
||||
- **覆盖年份范围**:1900-2100 年
|
||||
- **特殊场景覆盖**:春节、端午、中秋等传统节日,闰月处理
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 核心操作性能
|
||||
| 操作 | 性能 | 内存分配 |
|
||||
|------|------|----------|
|
||||
| FromStdTime | 1,930 ns/op | 48 B/op |
|
||||
| ToGregorian | 1,835 ns/op | 48 B/op |
|
||||
| IsLeapYear | 23.20 ns/op | 48 B/op |
|
||||
| IsValid | 1.167 ns/op | 0 B/op |
|
||||
|
||||
### 格式化操作性能
|
||||
| 操作 | 性能 | 内存分配 |
|
||||
|------|------|----------|
|
||||
| String | 141.7 ns/op | 24 B/op |
|
||||
| ToYearString | 618.5 ns/op | 56 B/op |
|
||||
| ToMonthString | 22.73 ns/op | 8 B/op |
|
||||
| ToDayString | 23.04 ns/op | 8 B/op |
|
||||
| ToDateString | 707.0 ns/op | 104 B/op |
|
||||
|
||||
### 生肖与节日性能
|
||||
| 操作 | 性能 | 内存分配 |
|
||||
|------|------|----------|
|
||||
| Animal | 1.352 ns/op | 0 B/op |
|
||||
| Festival | 80.86 ns/op | 4 B/op |
|
||||
| AnimalYearChecks | 30.57 ns/op | 48 B/op |
|
||||
|
||||
### 内部计算性能
|
||||
| 操作 | 性能 | 内存分配 |
|
||||
|------|------|----------|
|
||||
| LeapMonth | 20.24 ns/op | 48 B/op |
|
||||
| IsLeapMonth | 1.305 ns/op | 0 B/op |
|
||||
| GetDaysInYear | 33.11 ns/op | 48 B/op |
|
||||
| GetDaysInMonth | 1.005 ns/op | 0 B/op |
|
||||
| GetOffsetInYear | 21.18 ns/op | 48 B/op |
|
||||
|
||||
## 算法验证
|
||||
|
||||
### 权威性验证
|
||||
- **Python 权威库对比**:使用 `convertdate` 库生成权威测试数据
|
||||
- **测试用例覆盖**:165 个关键日期的双向转换验证
|
||||
- **验证结果**:所有测试用例通过,算法准确性得到权威验证
|
||||
|
||||
### 算法特点
|
||||
- **基于查表法**:使用预计算的农历数据表,确保准确性
|
||||
- **闰月处理**:完整的闰月计算和验证机制
|
||||
- **边界处理**:1900-2100 年范围的完整支持
|
||||
- **时区兼容**:支持不同时区的日期转换
|
||||
|
||||
### 数据完整性
|
||||
- **农历数据表**:包含 1900-2100 年的完整农历数据
|
||||
- **节日数据**:12 个主要传统节日的完整映射
|
||||
- **生肖周期**:12 年一个周期的生肖计算
|
||||
|
||||
## 质量评估
|
||||
|
||||
### 代码质量
|
||||
- **代码覆盖率**:100% 语句覆盖,确保所有代码路径都经过测试
|
||||
- **错误处理**:完善的错误处理机制,包括无效日期和时区处理
|
||||
- **边界测试**:完整的边界值测试,包括最小值和最大值
|
||||
- **异常情况**:零值时间、无效时区等异常情况的处理
|
||||
|
||||
### 性能质量
|
||||
- **高效算法**:基于查表法的快速计算,大部分操作在纳秒级别
|
||||
- **内存优化**:大部分操作内存分配为 0 或最小化
|
||||
- **并发安全**:无状态设计,支持并发使用
|
||||
|
||||
### 功能完整性
|
||||
- **功能完备**:涵盖农历日期的所有核心功能
|
||||
- **接口友好**:提供丰富的格式化选项和便捷方法
|
||||
- **扩展性**:支持自定义时区和格式化需求
|
||||
|
||||
### 可靠性评估
|
||||
- **权威验证**:通过 Python 权威库的 165 个测试用例验证
|
||||
- **边界测试**:完整的边界值测试确保稳定性
|
||||
- **错误处理**:完善的错误处理机制提高系统稳定性
|
||||
|
||||
## 总结
|
||||
|
||||
农历模块作为 Carbon 日期时间库的重要组成部分,提供了完整、准确、高效的农历日期处理功能。通过 100% 的代码覆盖率、165 个权威测试用例的验证,以及优秀的性能表现,该模块已经达到了生产环境的使用标准。
|
||||
|
||||
### 主要优势
|
||||
1. **准确性**:基于权威算法和大量测试数据验证
|
||||
2. **完整性**:涵盖农历日期的所有核心功能需求
|
||||
3. **高性能**:大部分操作在纳秒级别,内存使用优化
|
||||
4. **易用性**:提供丰富的格式化选项和便捷方法
|
||||
5. **可靠性**:完善的错误处理和边界测试
|
||||
|
||||
### 应用场景
|
||||
- 传统节日计算和显示
|
||||
- 农历日期转换和处理
|
||||
- 生肖年份判断
|
||||
- 中文日期格式化
|
||||
- 跨时区的农历日期处理
|
||||
|
||||
农历模块已经为各种需要农历日期处理的应用场景提供了可靠的技术支持。
|
||||
166
vendor/github.com/dromara/carbon/v2/calendar/lunar/test_report.en.md
generated
vendored
Normal file
166
vendor/github.com/dromara/carbon/v2/calendar/lunar/test_report.en.md
generated
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
# Lunar Calendar Test Report
|
||||
|
||||
## Overview
|
||||
|
||||
The Lunar Calendar is a crucial component of the Carbon date-time library, providing comprehensive lunar calendar date processing capabilities. This report details the functional features, test coverage, performance benchmarks, and quality assessment results of the Lunar Calendar.
|
||||
|
||||
## Functional Features
|
||||
|
||||
### Core Functions
|
||||
- **Lunar Date Creation and Validation**: Supports lunar date creation and validity verification within the range of 1900-2100
|
||||
- **Gregorian Conversion**: Bidirectional conversion between lunar dates and Gregorian dates
|
||||
- **Leap Month Processing**: Complete leap month calculation and verification mechanism
|
||||
- **Timezone Support**: Date conversion support for different timezones
|
||||
|
||||
### Formatting Functions
|
||||
- **Chinese Numerals Conversion**: Chinese numeral representation for years, months, and dates
|
||||
- **Lunar Month Representation**: Support for leap month identification (e.g., "闰二月")
|
||||
- **Complete Date String**: Generation of complete date descriptions like "二零二零年正月初一"
|
||||
- **Week Representation**: Weekday information for lunar dates
|
||||
|
||||
### Zodiac and Festivals
|
||||
- **Twelve Zodiac Animals**: Zodiac calculation based on years (Rat, Ox, Tiger, Rabbit, Dragon, Snake, Horse, Goat, Monkey, Rooster, Dog, Pig)
|
||||
- **Traditional Festivals**: Support for identification of 12 major traditional festivals
|
||||
- Spring Festival, Lantern Festival, Dragon Head Raising, Shangsi Festival, Dragon Boat Festival
|
||||
- Qixi Festival, Ghost Festival, Mid-Autumn Festival, Double Ninth Festival, Winter Clothing Festival, Xiayuan Festival, Laba Festival
|
||||
|
||||
### Validation Functions
|
||||
- **Year Validation**: Support for 1900-2100 range validation
|
||||
- **Month Validation**: 1-12 month range validation, including leap month processing
|
||||
- **Date Validation**: Date validity verification based on month days
|
||||
- **Zodiac Year Judgment**: Fast judgment methods for 12 zodiac year types
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Unit Test Statistics
|
||||
- **Total Test Cases**: 544 lines of test code
|
||||
- **Code Coverage**: 100.0% statement coverage
|
||||
- **Test Pass Rate**: 100% (all test cases passed)
|
||||
|
||||
### Test Categories
|
||||
1. **Basic Function Tests**
|
||||
- Maximum/minimum value boundary tests
|
||||
- Lunar date creation from standard time
|
||||
- Lunar to Gregorian conversion
|
||||
|
||||
2. **Formatting Function Tests**
|
||||
- Year, month, date string conversion
|
||||
- Complete date string generation
|
||||
- Week string generation
|
||||
|
||||
3. **Zodiac and Festival Tests**
|
||||
- Twelve zodiac calculation verification
|
||||
- Traditional festival identification tests
|
||||
|
||||
4. **Validation Function Tests**
|
||||
- Date validity verification
|
||||
- Leap year judgment
|
||||
- Leap month judgment
|
||||
- Zodiac year judgment
|
||||
|
||||
5. **Authority Data Validation**
|
||||
- 165 test cases based on Python authority library
|
||||
- Covers key dates from 1900-2100
|
||||
- Includes special scenarios like traditional festivals, leap months, boundary dates
|
||||
|
||||
### Test Data Scale
|
||||
- **Authority Test Cases**: 165
|
||||
- **Test Data File**: 2,311 lines of JSON data
|
||||
- **Year Coverage Range**: 1900-2100
|
||||
- **Special Scenario Coverage**: Traditional festivals like Spring Festival, Dragon Boat Festival, Mid-Autumn Festival, leap month processing
|
||||
|
||||
## Performance Benchmarks
|
||||
|
||||
### Core Operation Performance
|
||||
| Operation | Performance | Memory Allocation |
|
||||
|-----------|-------------|-------------------|
|
||||
| FromStdTime | 1,930 ns/op | 48 B/op |
|
||||
| ToGregorian | 1,835 ns/op | 48 B/op |
|
||||
| IsLeapYear | 23.20 ns/op | 48 B/op |
|
||||
| IsValid | 1.167 ns/op | 0 B/op |
|
||||
|
||||
### Formatting Operation Performance
|
||||
| Operation | Performance | Memory Allocation |
|
||||
|-----------|-------------|-------------------|
|
||||
| String | 141.7 ns/op | 24 B/op |
|
||||
| ToYearString | 618.5 ns/op | 56 B/op |
|
||||
| ToMonthString | 22.73 ns/op | 8 B/op |
|
||||
| ToDayString | 23.04 ns/op | 8 B/op |
|
||||
| ToDateString | 707.0 ns/op | 104 B/op |
|
||||
|
||||
### Zodiac and Festival Performance
|
||||
| Operation | Performance | Memory Allocation |
|
||||
|-----------|-------------|-------------------|
|
||||
| Animal | 1.352 ns/op | 0 B/op |
|
||||
| Festival | 80.86 ns/op | 4 B/op |
|
||||
| AnimalYearChecks | 30.57 ns/op | 48 B/op |
|
||||
|
||||
### Internal Calculation Performance
|
||||
| Operation | Performance | Memory Allocation |
|
||||
|-----------|-------------|-------------------|
|
||||
| LeapMonth | 20.24 ns/op | 48 B/op |
|
||||
| IsLeapMonth | 1.305 ns/op | 0 B/op |
|
||||
| GetDaysInYear | 33.11 ns/op | 48 B/op |
|
||||
| GetDaysInMonth | 1.005 ns/op | 0 B/op |
|
||||
| GetOffsetInYear | 21.18 ns/op | 48 B/op |
|
||||
|
||||
## Algorithm Verification
|
||||
|
||||
### Authority Verification
|
||||
- **Python Authority Library Comparison**: Uses `convertdate` library to generate authoritative test data
|
||||
- **Test Case Coverage**: Bidirectional conversion verification for 165 key dates
|
||||
- **Verification Results**: All test cases passed, algorithm accuracy verified by authority
|
||||
|
||||
### Algorithm Characteristics
|
||||
- **Table-based Method**: Uses pre-calculated lunar calendar data table to ensure accuracy
|
||||
- **Leap Month Processing**: Complete leap month calculation and verification mechanism
|
||||
- **Boundary Processing**: Complete support for 1900-2100 range
|
||||
- **Timezone Compatibility**: Date conversion support for different timezones
|
||||
|
||||
### Data Integrity
|
||||
- **Lunar Calendar Data Table**: Contains complete lunar calendar data for 1900-2100
|
||||
- **Festival Data**: Complete mapping of 12 major traditional festivals
|
||||
- **Zodiac Cycle**: 12-year cycle zodiac calculation
|
||||
|
||||
## Quality Assessment
|
||||
|
||||
### Code Quality
|
||||
- **Code Coverage**: 100% statement coverage ensures all code paths are tested
|
||||
- **Error Handling**: Comprehensive error handling mechanism including invalid dates and timezone processing
|
||||
- **Boundary Testing**: Complete boundary value testing including minimum and maximum values
|
||||
- **Exception Handling**: Processing of exceptional cases like zero time, invalid timezones
|
||||
|
||||
### Performance Quality
|
||||
- **Efficient Algorithm**: Fast calculation based on table lookup, most operations at nanosecond level
|
||||
- **Memory Optimization**: Most operations have 0 or minimized memory allocation
|
||||
- **Concurrency Safety**: Stateless design supports concurrent usage
|
||||
|
||||
### Functional Completeness
|
||||
- **Complete Functionality**: Covers all core lunar calendar date functions
|
||||
- **User-friendly Interface**: Provides rich formatting options and convenient methods
|
||||
- **Extensibility**: Supports custom timezone and formatting requirements
|
||||
|
||||
### Reliability Assessment
|
||||
- **Authority Verification**: Verified through 165 test cases from Python authority library
|
||||
- **Boundary Testing**: Complete boundary value testing ensures stability
|
||||
- **Error Handling**: Comprehensive error handling mechanism improves system stability
|
||||
|
||||
## Summary
|
||||
|
||||
The Lunar Calendar module, as a crucial component of the Carbon date-time library, provides complete, accurate, and efficient lunar calendar date processing capabilities. Through 100% code coverage, verification by 165 authoritative test cases, and excellent performance, this module has reached production environment standards.
|
||||
|
||||
### Key Advantages
|
||||
1. **Accuracy**: Based on authoritative algorithms and extensive test data verification
|
||||
2. **Completeness**: Covers all core lunar calendar date processing requirements
|
||||
3. **High Performance**: Most operations at nanosecond level with optimized memory usage
|
||||
4. **Usability**: Provides rich formatting options and convenient methods
|
||||
5. **Reliability**: Comprehensive error handling and boundary testing
|
||||
|
||||
### Application Scenarios
|
||||
- Traditional festival calculation and display
|
||||
- Lunar calendar date conversion and processing
|
||||
- Zodiac year judgment
|
||||
- Chinese date formatting
|
||||
- Cross-timezone lunar calendar date processing
|
||||
|
||||
The Lunar Calendar module has provided reliable technical support for various application scenarios requiring lunar calendar date processing.
|
||||
74
vendor/github.com/dromara/carbon/v2/calendar/persian/README.cn.md
generated
vendored
74
vendor/github.com/dromara/carbon/v2/calendar/persian/README.cn.md
generated
vendored
@@ -1,74 +0,0 @@
|
||||
# 波斯历(伊朗历)
|
||||
|
||||
简体中文 | [English](README.md) | [日本語](README.jp.md)
|
||||
|
||||
#### 用法示例
|
||||
|
||||
##### 将 `公历` 转换成 `波斯历`
|
||||
|
||||
```go
|
||||
// 获取波斯历年份
|
||||
carbon.Parse("2020-08-05").Persian().Year() // 1399
|
||||
// 获取波斯历月份
|
||||
carbon.Parse("2020-08-05").Persian().Month() // 5
|
||||
// 获取波斯历日期
|
||||
carbon.Parse("2020-08-05").Persian().Day() // 15
|
||||
// 获取波斯历小时
|
||||
carbon.Parse("2020-08-05").Persian().Hour() // 13
|
||||
// 获取波斯历分钟
|
||||
carbon.Parse("2020-08-05").Persian().Minute() // 14
|
||||
// 获取波斯历秒数
|
||||
carbon.Parse("2020-08-05").Persian().Second() // 15
|
||||
|
||||
// 获取波斯历日期时间字符串
|
||||
carbon.Parse("2020-08-05").Persian().String() // 1399-05-15
|
||||
fmt.Printf("%s", carbon.Parse("2020-08-05").Persian()) // 1399-05-15
|
||||
|
||||
// 获取波斯历月字符串
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString() // Mordad
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString("en") // Mordad
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString("fa") // مرداد
|
||||
|
||||
// 获取简写波斯历月字符串
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString() // Mor
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString("en") // Mor
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString("fa") // مرد
|
||||
|
||||
// 获取波斯历周字符串
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString() // Chaharshanbeh
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString("en") // Chaharshanbeh
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString("fa") // چهارشنبه
|
||||
|
||||
// 获取简写波斯历周字符串
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString() // Cha
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString("en") // Cha
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString("fa") // د
|
||||
|
||||
```
|
||||
|
||||
##### 将 `波斯历` 转化成 `公历`
|
||||
|
||||
```go
|
||||
carbon.CreateFromPersian(1, 1, 1).ToDateTimeString() // 2016-03-20 00:00:00
|
||||
carbon.CreateFromPersian(622, 1, 1).ToDateTimeString() // 1243-03-21 00:00:00
|
||||
carbon.CreateFromPersian(1395, 1, 1).ToDateTimeString() // 2016-03-20 00:00:00
|
||||
carbon.CreateFromPersian(9377, 1, 1).ToDateTimeString() // 9998-03-19 00:00:00
|
||||
```
|
||||
|
||||
##### 日期判断
|
||||
```go
|
||||
// 是否是合法的波斯历日期
|
||||
carbon.CreateFromPersian(1, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(622, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(9377, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(0, 0, 0, 0).IsValid() // false
|
||||
carbon.CreateFromPersian(2024, 0, 1).IsValid() // false
|
||||
carbon.CreateFromPersian(2024, 1, 0).IsValid() // false
|
||||
|
||||
// 是否是波斯历闰年
|
||||
carbon.CreateFromPersian(1395, 1, 1).IsLeapYear() // true
|
||||
carbon.CreateFromPersian(9377, 1, 1).IsLeapYear() // true
|
||||
carbon.CreateFromPersian(622, 1, 1).IsLeapYear() // false
|
||||
carbon.CreateFromPersian(9999, 1, 1).IsLeapYear() // false
|
||||
|
||||
```
|
||||
73
vendor/github.com/dromara/carbon/v2/calendar/persian/README.jp.md
generated
vendored
73
vendor/github.com/dromara/carbon/v2/calendar/persian/README.jp.md
generated
vendored
@@ -1,73 +0,0 @@
|
||||
# ペルシア暦(イラン暦)
|
||||
|
||||
日本語 | [English](README.md) | [简体中文](README.cn.md)
|
||||
|
||||
#### 使い方の例
|
||||
|
||||
##### `西暦` を `ペルシャ暦` に変換
|
||||
|
||||
```go
|
||||
// ペルシャ暦の取得
|
||||
carbon.Parse("2020-08-05").Persian().Year() // 1399
|
||||
// ペルシャ暦月の取得
|
||||
carbon.Parse("2020-08-05").Persian().Month() // 5
|
||||
// ペルシャ暦の取得日
|
||||
carbon.Parse("2020-08-05").Persian().Day() // 15
|
||||
// ペルシャ暦時間の取得
|
||||
carbon.Parse("2020-08-05").Persian().Hour() // 13
|
||||
// ペルシャ暦分の取得
|
||||
carbon.Parse("2020-08-05").Persian().Minute() // 14
|
||||
// ペルシャ暦秒の取得
|
||||
carbon.Parse("2020-08-05").Persian().Second() // 15
|
||||
|
||||
// ペルシャ暦日時文字列の取得
|
||||
carbon.Parse("2020-08-05").Persian().String() // 1399-05-15
|
||||
fmt.Printf("%s", carbon.Parse("2020-08-05").Persian()) // 1399-05-15
|
||||
|
||||
// ペルシア暦月文字列の取得
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString() // Mordad
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString("en") // Mordad
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString("fa") // مرداد
|
||||
|
||||
// 略語ペルシャ暦文字列の取得
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString() // Mor
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString("en") // Mor
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString("fa") // مرد
|
||||
|
||||
// ペルシャ暦週文字列の取得
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString() // Chaharshanbeh
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString("en") // Chaharshanbeh
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString("fa") // چهارشنبه
|
||||
|
||||
// 略語ペルシャ暦週文字列の取得
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString() // Cha
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString("en") // Cha
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString("fa") // د
|
||||
```
|
||||
|
||||
##### ペルシャ暦を西暦に変換する
|
||||
|
||||
```go
|
||||
carbon.CreateFromPersian(1, 1, 1).ToDateTimeString() // 2016-03-20 00:00:00
|
||||
carbon.CreateFromPersian(622, 1, 1).ToDateTimeString() // 1243-03-21 00:00:00
|
||||
carbon.CreateFromPersian(1395, 1, 1).ToDateTimeString() // 2016-03-20 00:00:00
|
||||
carbon.CreateFromPersian(9377, 1, 1).ToDateTimeString() // 9998-03-19 00:00:00
|
||||
```
|
||||
|
||||
##### 日付判断
|
||||
```go
|
||||
// 合法的なペルシャ暦の日付かどうか
|
||||
carbon.CreateFromPersian(1, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(622, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(9377, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(0, 0, 0, 0).IsValid() // false
|
||||
carbon.CreateFromPersian(2024, 0, 1).IsValid() // false
|
||||
carbon.CreateFromPersian(2024, 1, 0).IsValid() // false
|
||||
|
||||
// ペルシア暦閏年かどうか
|
||||
carbon.CreateFromPersian(1395, 1, 1).IsLeapYear() // true
|
||||
carbon.CreateFromPersian(9377, 1, 1).IsLeapYear() // true
|
||||
carbon.CreateFromPersian(622, 1, 1).IsLeapYear() // false
|
||||
carbon.CreateFromPersian(9999, 1, 1).IsLeapYear() // false
|
||||
|
||||
```
|
||||
74
vendor/github.com/dromara/carbon/v2/calendar/persian/README.md
generated
vendored
74
vendor/github.com/dromara/carbon/v2/calendar/persian/README.md
generated
vendored
@@ -1,74 +0,0 @@
|
||||
# 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").Persian().Year() // 1399
|
||||
// Get persian month
|
||||
carbon.Parse("2020-08-05").Persian().Month() // 5
|
||||
// Get persian day
|
||||
carbon.Parse("2020-08-05").Persian().Day() // 15
|
||||
// Get persian hour
|
||||
carbon.Parse("2020-08-05").Persian().Hour() // 13
|
||||
// Get persian minute
|
||||
carbon.Parse("2020-08-05").Persian().Minute() // 14
|
||||
// Get persian second
|
||||
carbon.Parse("2020-08-05").Persian().Second() // 15
|
||||
|
||||
// Get persian date and time string
|
||||
carbon.Parse("2020-08-05").Persian().String() // 1399-05-15
|
||||
fmt.Printf("%s", carbon.Parse("2020-08-05").Persian()) // 1399-05-15
|
||||
|
||||
// Get persian month as string
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString() // Mordad
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString("en") // Mordad
|
||||
carbon.Parse("2020-08-05").Persian().ToMonthString("fa") // مرداد
|
||||
|
||||
// Get persian short month as string
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString() // Mor
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString("en") // Mor
|
||||
carbon.Parse("2020-08-05").Persian().ToShortMonthString("fa") // مرد
|
||||
|
||||
// Get persian week as string
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString() // Chaharshanbeh
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString("en") // Chaharshanbeh
|
||||
carbon.Parse("2020-08-05").Persian().ToWeekString("fa") // چهارشنبه
|
||||
|
||||
// Get persian short week as string
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString() // Cha
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString("en") // Cha
|
||||
carbon.Parse("2020-08-05").Persian().ToShortWeekString("fa") // د
|
||||
|
||||
```
|
||||
|
||||
##### Convert `Persian` calendar to `Gregorian` calendar
|
||||
|
||||
```go
|
||||
carbon.CreateFromPersian(1, 1, 1).ToDateTimeString() // 2016-03-20 00:00:00
|
||||
carbon.CreateFromPersian(622, 1, 1).ToDateTimeString() // 1243-03-21 00:00:00
|
||||
carbon.CreateFromPersian(1395, 1, 1).ToDateTimeString() // 2016-03-20 00:00:00
|
||||
carbon.CreateFromPersian(9377, 1, 1).ToDateTimeString() // 9998-03-19 00:00:00
|
||||
```
|
||||
|
||||
##### Comparison
|
||||
```go
|
||||
// Whether is a valid persian date
|
||||
carbon.CreateFromPersian(1, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(622, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(9377, 1, 1).IsValid() // true
|
||||
carbon.CreateFromPersian(0, 0, 0, 0).IsValid() // false
|
||||
carbon.CreateFromPersian(2024, 0, 1).IsValid() // false
|
||||
carbon.CreateFromPersian(2024, 1, 0).IsValid() // false
|
||||
|
||||
// Whether is a persian leap year
|
||||
carbon.CreateFromPersian(1395, 1, 1).IsLeapYear() // true
|
||||
carbon.CreateFromPersian(9377, 1, 1).IsLeapYear() // true
|
||||
carbon.CreateFromPersian(622, 1, 1).IsLeapYear() // false
|
||||
carbon.CreateFromPersian(9999, 1, 1).IsLeapYear() // false
|
||||
|
||||
```
|
||||
234
vendor/github.com/dromara/carbon/v2/calendar/persian/persian.go
generated
vendored
234
vendor/github.com/dromara/carbon/v2/calendar/persian/persian.go
generated
vendored
@@ -3,7 +3,6 @@ package persian
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"time"
|
||||
|
||||
"github.com/dromara/carbon/v2/calendar"
|
||||
@@ -12,29 +11,20 @@ import (
|
||||
|
||||
type Locale string
|
||||
|
||||
const EnLocale Locale = "en"
|
||||
const FaLocale Locale = "fa"
|
||||
|
||||
const defaultLocale = EnLocale
|
||||
|
||||
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{"پ", "چ", "س", "د", "ی", "ش", "ج"}
|
||||
const (
|
||||
EnLocale Locale = "en"
|
||||
FaLocale Locale = "fa"
|
||||
defaultLocale = EnLocale
|
||||
persianEpoch = 1948320
|
||||
)
|
||||
|
||||
// ErrInvalidPersian returns a invalid persian date.
|
||||
var ErrInvalidPersian = func() error {
|
||||
return fmt.Errorf("invalid persian date, please make sure the persian date is valid")
|
||||
}
|
||||
var (
|
||||
EnMonths = []string{"Farvardin", "Ordibehesht", "Khordad", "Tir", "Mordad", "Shahrivar", "Mehr", "Aban", "Azar", "Dey", "Bahman", "Esfand"}
|
||||
FaMonths = []string{"فروردین", "اردیبهشت", "خرداد", "تیر", "مرداد", "شهریور", "مهر", "آبان", "آذر", "دی", "بهمن", "اسفند"}
|
||||
|
||||
EnWeeks = []string{"Yekshanbeh", "Doshanbeh", "Seshanbeh", "Chaharshanbeh", "Panjshanbeh", "Jomeh", "Shanbeh"}
|
||||
FaWeeks = []string{"نجشنبه", "دوشنبه", "سه شنبه", "چهارشنبه", "پنجشنبه", "جمعه", "شنبه"}
|
||||
)
|
||||
|
||||
// Persian defines a Persian struct.
|
||||
type Persian struct {
|
||||
@@ -44,55 +34,21 @@ type Persian struct {
|
||||
|
||||
// NewPersian returns a new Persian instance.
|
||||
func NewPersian(year, month, day int) *Persian {
|
||||
p := new(Persian)
|
||||
p.year, p.month, p.day = year, month, day
|
||||
p := &Persian{year: year, month: month, day: day}
|
||||
if !p.IsValid() {
|
||||
p.Error = ErrInvalidPersian()
|
||||
p.Error = fmt.Errorf("invalid persian date: %04d-%02d-%02d", year, month, day)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
// MaxValue returns a Persian instance for the greatest supported date.
|
||||
func MaxValue() *Persian {
|
||||
return &Persian{
|
||||
year: 9377,
|
||||
month: 12,
|
||||
day: 31,
|
||||
}
|
||||
}
|
||||
|
||||
// MinValue returns a Persian instance for the lowest supported date.
|
||||
func MinValue() *Persian {
|
||||
return &Persian{
|
||||
year: 1,
|
||||
month: 1,
|
||||
day: 1,
|
||||
}
|
||||
}
|
||||
|
||||
// FromStdTime creates a Persian instance from standard time.Time.
|
||||
func FromStdTime(t time.Time) *Persian {
|
||||
p := new(Persian)
|
||||
func FromStdTime(t time.Time) (p *Persian) {
|
||||
if t.IsZero() {
|
||||
return nil
|
||||
}
|
||||
gjdn := int(julian.FromStdTime(time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())).JD(0))
|
||||
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
|
||||
return p
|
||||
year, month, day := jdn2persian(gjdn)
|
||||
return &Persian{year: year, month: month, day: day}
|
||||
}
|
||||
|
||||
// ToGregorian converts Persian instance to Gregorian instance.
|
||||
@@ -109,22 +65,23 @@ func (p *Persian) ToGregorian(timezone ...string) *calendar.Gregorian {
|
||||
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
|
||||
day := l - 2447*j/80
|
||||
l = j / 11
|
||||
m := j + 2 - 12*l
|
||||
y := 100*(n-49) + i + l
|
||||
month := j + 2 - 12*l
|
||||
year := 100*(n-49) + i + l
|
||||
|
||||
g.Time = time.Date(y, time.Month(m), d, 0, 0, 0, 0, loc)
|
||||
g.Time = time.Date(year, time.Month(month), day, 0, 0, 0, 0, loc)
|
||||
return g
|
||||
}
|
||||
|
||||
// Year gets lunar year like 2020.
|
||||
// Year gets the Persian year like 2020.
|
||||
func (p *Persian) Year() int {
|
||||
if !p.IsValid() {
|
||||
return 0
|
||||
@@ -132,7 +89,7 @@ func (p *Persian) Year() int {
|
||||
return p.year
|
||||
}
|
||||
|
||||
// Month gets lunar month like 8.
|
||||
// Month gets the Persian month like 8.
|
||||
func (p *Persian) Month() int {
|
||||
if !p.IsValid() {
|
||||
return 0
|
||||
@@ -140,7 +97,7 @@ func (p *Persian) Month() int {
|
||||
return p.month
|
||||
}
|
||||
|
||||
// Day gets lunar day like 5.
|
||||
// Day gets the Persian day like 5.
|
||||
func (p *Persian) Day() int {
|
||||
if !p.IsValid() {
|
||||
return 0
|
||||
@@ -148,7 +105,7 @@ func (p *Persian) Day() int {
|
||||
return p.day
|
||||
}
|
||||
|
||||
// String implements "Stringer" interface for Persian.
|
||||
// String implements the "Stringer" interface for Persian.
|
||||
func (p *Persian) String() string {
|
||||
if !p.IsValid() {
|
||||
return ""
|
||||
@@ -156,7 +113,7 @@ func (p *Persian) String() string {
|
||||
return fmt.Sprintf("%04d-%02d-%02d", p.year, p.month, p.day)
|
||||
}
|
||||
|
||||
// ToMonthString outputs a string in persian month format like "فروردین".
|
||||
// ToMonthString outputs a string in Persian month format like "فروردین".
|
||||
func (p *Persian) ToMonthString(locale ...Locale) (month string) {
|
||||
if !p.IsValid() {
|
||||
return ""
|
||||
@@ -174,24 +131,6 @@ func (p *Persian) ToMonthString(locale ...Locale) (month string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToShortMonthString outputs a short string in persian month format like "فروردین".
|
||||
func (p *Persian) ToShortMonthString(locale ...Locale) (month string) {
|
||||
if !p.IsValid() {
|
||||
return ""
|
||||
}
|
||||
loc := defaultLocale
|
||||
if len(locale) > 0 {
|
||||
loc = locale[0]
|
||||
}
|
||||
switch loc {
|
||||
case EnLocale:
|
||||
return ShortEnMonths[p.month-1]
|
||||
case FaLocale:
|
||||
return ShortFaMonths[p.month-1]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToWeekString outputs a string in week layout like "چهارشنبه".
|
||||
func (p *Persian) ToWeekString(locale ...Locale) (month string) {
|
||||
if !p.IsValid() {
|
||||
@@ -211,56 +150,89 @@ func (p *Persian) ToWeekString(locale ...Locale) (month string) {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ToShortWeekString outputs a short string in week layout like "چهارشنبه".
|
||||
func (p *Persian) ToShortWeekString(locale ...Locale) (month string) {
|
||||
if !p.IsValid() {
|
||||
return ""
|
||||
}
|
||||
loc := defaultLocale
|
||||
if len(locale) > 0 {
|
||||
loc = locale[0]
|
||||
}
|
||||
week := p.ToGregorian().Time.Weekday()
|
||||
switch loc {
|
||||
case EnLocale:
|
||||
return ShortEnWeeks[week]
|
||||
case FaLocale:
|
||||
return ShortFaWeeks[week]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// IsValid reports whether is a valid persian date.
|
||||
// IsValid reports whether the Persian date is valid.
|
||||
func (p *Persian) IsValid() bool {
|
||||
if p == nil || p.Error != nil {
|
||||
return false
|
||||
}
|
||||
if p.year >= MinValue().year && p.year <= MaxValue().year {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLeapYear reports whether is a persian leap year.
|
||||
func (p *Persian) IsLeapYear() bool {
|
||||
if !p.IsValid() {
|
||||
// Check year range validation (Persian calendar starts from 622 CE)
|
||||
if p.year < 1 || p.year > 9999 || p.month <= 0 || p.month > 12 || p.day <= 0 || p.day > 31 {
|
||||
return false
|
||||
}
|
||||
return (25*p.year+11)%33 < 8
|
||||
// Check month-specific day validation
|
||||
if p.month > 6 && p.month <= 11 && p.day > 30 {
|
||||
return false
|
||||
}
|
||||
if p.month == 12 {
|
||||
// Use IsLeapYear method
|
||||
if (!p.IsLeapYear() && p.day > 29) || (p.IsLeapYear() && p.day > 30) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// gets Julian day number in Persian calendar
|
||||
func getPersianJdn(year, month, day int) int {
|
||||
year = year - 473
|
||||
if year >= 0 {
|
||||
year--
|
||||
// IsLeapYear reports whether the Persian year is a leap year.
|
||||
func (p *Persian) IsLeapYear() bool {
|
||||
if p == nil || p.Error != nil {
|
||||
return false
|
||||
}
|
||||
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
|
||||
currentYearJdn := getPersianJdn(p.year, 1, 1)
|
||||
nextYearJdn := getPersianJdn(p.year+1, 1, 1)
|
||||
daysDiff := nextYearJdn - currentYearJdn
|
||||
return daysDiff > 365
|
||||
}
|
||||
|
||||
// getPersianYear gets the Persian year from Julian Day Number.
|
||||
func getPersianYear(jdn int) int {
|
||||
days := jdn - persianEpoch
|
||||
year := 474 + days/365
|
||||
if year < 1 || year > 9999 {
|
||||
return -1
|
||||
}
|
||||
low := 1
|
||||
high := 9999
|
||||
for low <= high {
|
||||
mid := (low + high) / 2
|
||||
yearStartJdn := getPersianJdn(mid, 1, 1)
|
||||
nextYearStartJdn := getPersianJdn(mid+1, 1, 1)
|
||||
if jdn >= yearStartJdn && jdn < nextYearStartJdn {
|
||||
return mid
|
||||
}
|
||||
if jdn < yearStartJdn {
|
||||
high = mid - 1
|
||||
} else {
|
||||
low = mid + 1
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// getPersianJdn gets the Julian day number in the Persian calendar.
|
||||
func getPersianJdn(year, month, day int) int {
|
||||
yearOffset := year - 474
|
||||
if yearOffset < 0 {
|
||||
yearOffset--
|
||||
}
|
||||
cycleYear := 474 + (yearOffset % 2820)
|
||||
var monthDays int
|
||||
if month <= 7 {
|
||||
monthDays = (month - 1) * 31
|
||||
} else {
|
||||
monthDays = (month-1)*30 + 6
|
||||
}
|
||||
return day + monthDays + (cycleYear*682-110)/2816 + (cycleYear-1)*365 + yearOffset/2820*1029983 + persianEpoch
|
||||
}
|
||||
|
||||
// jdn2persian converts Julian Day Number to Persian date (year, month, day).
|
||||
func jdn2persian(jdn int) (year, month, day int) {
|
||||
year = getPersianYear(jdn)
|
||||
days := jdn - getPersianJdn(year, 1, 1) + 1
|
||||
if days <= 186 {
|
||||
month = (days-1)/31 + 1
|
||||
} else {
|
||||
month = (days-186-1)/30 + 7
|
||||
}
|
||||
day = jdn - getPersianJdn(year, month, 1) + 1
|
||||
return
|
||||
}
|
||||
|
||||
22076
vendor/github.com/dromara/carbon/v2/calendar/persian/persian_test_data.json
generated
vendored
Normal file
22076
vendor/github.com/dromara/carbon/v2/calendar/persian/persian_test_data.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
139
vendor/github.com/dromara/carbon/v2/calendar/persian/test_report.cn.md
generated
vendored
Normal file
139
vendor/github.com/dromara/carbon/v2/calendar/persian/test_report.cn.md
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
# 波斯历(Persian)测试报告
|
||||
|
||||
## 概述
|
||||
|
||||
本报告详细记录了 `calendar/persian` 包的测试情况,包括功能特性、测试覆盖情况、性能基准和质量评估结果。
|
||||
|
||||
## 功能特性
|
||||
|
||||
### 核心功能
|
||||
- **波斯历日期创建与验证**:支持波斯历日期的创建和有效性验证
|
||||
- **公历转换**:波斯历日期与公历日期之间的双向转换
|
||||
- **闰年处理**:完整的闰年计算和验证机制
|
||||
- **时区支持**:支持不同时区的日期转换
|
||||
|
||||
### 格式化功能
|
||||
- **多语言支持**:支持英文和波斯文两种语言环境
|
||||
- **月份名称**:英文月份名(Farvardin, Ordibehesht等)和波斯文月份名(فروردین, اردیبهشت等)
|
||||
- **星期名称**:英文星期名(Yekshanbeh, Doshanbeh等)和波斯文星期名(نجشنبه, دوشنبه等)
|
||||
- **日期字符串**:生成"YYYY-MM-DD"格式的日期字符串
|
||||
|
||||
### 算法特性
|
||||
- **闰年判断**:基于波斯历规则的闰年计算(通过JDN差分判定)
|
||||
- **月份天数**:动态计算每个月的天数(29/30/31天)
|
||||
- **JDN转换**:基于儒略日数的精确日期转换
|
||||
|
||||
### 验证功能
|
||||
- **年份验证**:支持广泛的年份范围验证(1-9999年)
|
||||
- **月份验证**:1-12月范围验证
|
||||
- **日期验证**:基于月份天数的日期有效性验证
|
||||
- **边界处理**:完善的边界条件和错误处理
|
||||
|
||||
## 测试覆盖
|
||||
|
||||
### 单元测试统计
|
||||
- **测试用例总数**:468 行测试代码
|
||||
- **代码覆盖率**:100.0% 语句覆盖
|
||||
- **测试通过率**:100%(所有测试用例通过)
|
||||
|
||||
### 测试分类
|
||||
1. **基础功能测试**
|
||||
- 波斯历日期创建与有效性验证
|
||||
- 波斯历与公历的双向转换
|
||||
- 时区处理测试
|
||||
2. **格式化功能测试**
|
||||
- 年份、月份、日期获取
|
||||
- 月份名称字符串转换(英文/波斯文)
|
||||
- 星期名称字符串转换(英文/波斯文)
|
||||
- 日期字符串格式化
|
||||
3. **算法功能测试**
|
||||
- 闰年判断测试
|
||||
- JDN转换测试
|
||||
- 月份天数计算测试
|
||||
4. **边界条件测试**
|
||||
- 零值处理
|
||||
- 无效输入处理
|
||||
- 边界年份测试
|
||||
- 错误时区处理
|
||||
5. **权威数据验证**
|
||||
- 基于Python convertdate权威库的1698个测试用例
|
||||
- 覆盖1400-1469年区间所有新年、每月首日、每月末日、非闰年最后一天、典型随机日期
|
||||
- 双向转换一致性验证
|
||||
|
||||
### 测试数据
|
||||
- **权威测试用例**:1698个测试用例
|
||||
- **测试数据文件**:22,076行JSON数据
|
||||
- **覆盖年份范围**:1400-1469年
|
||||
- **典型日期覆盖**:新年、每月首日、每月末日、非闰年最后一天、随机日期
|
||||
|
||||
## 性能基准
|
||||
|
||||
### 核心操作性能(示例,需根据实际基准测试结果补充)
|
||||
- **FromStdTime**:约 1,000 ns/op
|
||||
- **ToGregorian**:约 300 ns/op
|
||||
- **IsLeapYear**:< 1 ns/op
|
||||
- **IsValid**:< 2 ns/op
|
||||
- **String**:< 1 ns/op
|
||||
- **ToMonthString**:< 1 ns/op
|
||||
- **ToWeekString**:< 2 ns/op
|
||||
|
||||
> 具体性能数据可通过 `go test -bench .` 获取,波斯历模块整体性能优异,满足高并发和大批量日期处理需求。
|
||||
|
||||
## 算法验证
|
||||
|
||||
### 权威性验证
|
||||
- **Python权威库**:基于 `convertdate` 库的 `persian` 模块
|
||||
- **测试用例数量**:1698个权威测试用例
|
||||
- **验证范围**:1400-1469年波斯历
|
||||
- **验证内容**:新年、每月首日、每月末日、非闰年最后一天、典型随机日期
|
||||
- **双向一致性**:波斯历与公历互转完全一致
|
||||
|
||||
### 算法特点
|
||||
- **基于JDN**:使用儒略日数作为中间转换标准
|
||||
- **高精度计算**:支持高精度日期转换
|
||||
- **闰年处理**:完整的闰年判定与末日处理
|
||||
- **边界处理**:完善的边界条件和错误处理
|
||||
|
||||
### 数据完整性
|
||||
- **月份映射**:完整的英文和波斯文月份名称
|
||||
- **星期映射**:完整的英文和波斯文星期名称
|
||||
- **算法常数**:波斯历纪元(1948320)
|
||||
- **闰年规则**:基于JDN差分的精确判定
|
||||
|
||||
## 质量评估
|
||||
|
||||
### 代码质量
|
||||
- **覆盖率**:100% 语句覆盖率
|
||||
- **错误处理**:完善的 `nil` 指针和边界条件处理
|
||||
- **代码结构**:清晰的模块化设计
|
||||
- **文档注释**:详细的方法和常量注释
|
||||
|
||||
### 性能质量
|
||||
- **高效算法**:优化的 `JDN` 转换算法
|
||||
- **内存优化**:最小化内存分配
|
||||
- **并发安全**:无状态设计,支持并发使用
|
||||
- **时区支持**:完整的时区处理能力
|
||||
|
||||
### 功能完整性
|
||||
- **功能完备**:覆盖波斯历所有核心功能
|
||||
- **接口友好**:简洁易用的API设计
|
||||
- **扩展性强**:支持多语言环境扩展
|
||||
- **兼容性好**:与Carbon库其他模块良好集成
|
||||
|
||||
### 可靠性评估
|
||||
- **权威验证**:通过 `Python` 权威库验证
|
||||
- **边界测试**:完善的边界条件测试
|
||||
- **错误处理**:健壮的错误处理机制
|
||||
- **一致性**:双向转换的一致性保证
|
||||
|
||||
## 结论
|
||||
|
||||
波斯历模块是一个高质量、功能完备的波斯历处理库,具有以下特点:
|
||||
|
||||
1. **技术先进**:采用高精度JDN算法和最佳实践
|
||||
2. **功能完整**:覆盖波斯历处理的所有核心需求
|
||||
3. **性能优异**:高效的算法实现和优化的内存使用
|
||||
4. **质量可靠**:100%测试覆盖率和权威验证
|
||||
5. **易于使用**:简洁的API设计和完善的文档
|
||||
|
||||
该模块为波斯历处理提供了可靠的技术基础,是 `Carbon` 日期时间库的重要组成部分。
|
||||
149
vendor/github.com/dromara/carbon/v2/calendar/persian/test_report.en.md
generated
vendored
Normal file
149
vendor/github.com/dromara/carbon/v2/calendar/persian/test_report.en.md
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
# Persian Calendar Module Test Report
|
||||
|
||||
## Overview
|
||||
|
||||
This report details the testing status of the `calendar/persian` package, including functional features, test coverage, performance benchmarks, and quality assessment results.
|
||||
|
||||
## Functional Features
|
||||
|
||||
### Core Functions
|
||||
- **Persian Date Creation and Validation**: Support for creating and validating Persian calendar dates
|
||||
- **Gregorian Conversion**: Bidirectional conversion between Persian and Gregorian dates
|
||||
- **Leap Year Handling**: Complete leap year calculation and validation mechanism
|
||||
- **Timezone Support**: Date conversion support for different timezones
|
||||
|
||||
### Formatting Features
|
||||
- **Multi-language Support**: Support for English and Persian language environments
|
||||
- **Month Names**: English month names (Farvardin, Ordibehesht, etc.) and Persian month names (فروردین, اردیبهشت, etc.)
|
||||
- **Weekday Names**: English weekday names (Yekshanbeh, Doshanbeh, etc.) and Persian weekday names (یکشنبه, دوشنبه, etc.)
|
||||
- **Date Strings**: Generate date strings in "YYYY-MM-DD" format
|
||||
|
||||
### Algorithm Features
|
||||
- **Leap Year Determination**: Leap year calculation based on Persian calendar rules (determined by JDN difference)
|
||||
- **Month Days**: Dynamic calculation of days in each month (29/30/31 days)
|
||||
- **JDN Conversion**: Precise date conversion based on Julian Day Numbers
|
||||
|
||||
### Validation Features
|
||||
- **Year Validation**: Support for wide year range validation (1-9999 years)
|
||||
- **Month Validation**: 1-12 month range validation
|
||||
- **Date Validation**: Date validity validation based on month days
|
||||
- **Boundary Handling**: Comprehensive boundary conditions and error handling
|
||||
|
||||
## Test Coverage
|
||||
|
||||
### Unit Test Statistics
|
||||
- **Total Test Cases**: 468 lines of test code
|
||||
- **Code Coverage**: 100.0% statement coverage
|
||||
- **Test Pass Rate**: 100% (all test cases pass)
|
||||
|
||||
### Test Categories
|
||||
1. **Basic Function Tests**
|
||||
- Persian date creation and validation
|
||||
- Gregorian date conversion
|
||||
- Leap year determination
|
||||
- Month and day validation
|
||||
|
||||
2. **Formatting Tests**
|
||||
- English and Persian language formatting
|
||||
- Month and weekday name generation
|
||||
- Date string formatting
|
||||
|
||||
3. **Boundary Tests**
|
||||
- Extreme year values (1, 9999)
|
||||
- Invalid month and day values
|
||||
- Nil pointer handling
|
||||
|
||||
4. **Error Handling Tests**
|
||||
- Invalid date creation
|
||||
- Error state handling
|
||||
- Boundary condition processing
|
||||
|
||||
### Authority Data Validation
|
||||
- **Python Authority Library**: Based on the `persian` module of the `convertdate` library
|
||||
- **Number of Test Cases**: 1,698 authoritative test cases
|
||||
- **Validation Range**: Persian calendar years 1400-1469
|
||||
- **Validation Results**: 100% pass rate
|
||||
- **Test Coverage**: Persian New Year, first/last days of months, leap year handling, random dates
|
||||
|
||||
## Performance Benchmarks
|
||||
|
||||
### Benchmark Test Results
|
||||
The Persian calendar module includes comprehensive performance benchmarks covering all major operations:
|
||||
|
||||
```
|
||||
BenchmarkPersian_ToGregorian-8 1000000 1234 ns/op
|
||||
BenchmarkPersian_ToCarbon-8 1000000 1567 ns/op
|
||||
BenchmarkPersian_String-8 1000000 890 ns/op
|
||||
BenchmarkPersian_IsLeapYear-8 1000000 456 ns/op
|
||||
```
|
||||
|
||||
### Performance Analysis
|
||||
- **Conversion Performance**: Persian to Gregorian conversion averages 1.2μs per operation
|
||||
- **Carbon Integration**: Integration with Carbon library averages 1.6μs per operation
|
||||
- **String Formatting**: Date string generation averages 0.9μs per operation
|
||||
- **Leap Year Check**: Leap year determination averages 0.5μs per operation
|
||||
|
||||
### Performance Characteristics
|
||||
- **High Efficiency**: Optimized algorithms ensure fast date processing
|
||||
- **Memory Optimization**: Minimal memory allocation during operations
|
||||
- **Scalability**: Consistent performance across different date ranges
|
||||
- **Concurrency Support**: Stateless design supports concurrent usage
|
||||
|
||||
## Algorithm Verification
|
||||
|
||||
### Authority Algorithm
|
||||
- **Reference Implementation**: Python `convertdate.persian` module
|
||||
- **Algorithm Consistency**: Core conversion algorithms match authoritative implementation
|
||||
- **Leap Year Rules**: Persian calendar leap year rules correctly implemented
|
||||
- **Month Length Calculation**: Accurate calculation of month lengths (29/30/31 days)
|
||||
|
||||
### JDN Conversion
|
||||
- **Julian Day Number**: Based on precise JDN calculation
|
||||
- **Epoch Handling**: Correct handling of Persian calendar epoch
|
||||
- **Boundary Processing**: Proper processing of calendar boundaries
|
||||
- **Precision**: High-precision date conversion without loss of accuracy
|
||||
|
||||
### Validation Results
|
||||
- **Modern Dates**: All modern Persian dates (1400-1469) pass authority validation
|
||||
- **Leap Year Handling**: Correct identification and processing of leap years
|
||||
- **Month Boundaries**: Accurate handling of month start and end dates
|
||||
- **Year Boundaries**: Proper processing of year boundaries and transitions
|
||||
|
||||
## Quality Assessment
|
||||
|
||||
### Code Quality
|
||||
- **Coverage**: 100% statement coverage
|
||||
- **Error Handling**: Comprehensive `nil` pointer and boundary condition handling
|
||||
- **Code Structure**: Clear modular design
|
||||
- **Documentation**: Detailed method and constant documentation
|
||||
|
||||
### Performance Quality
|
||||
- **Efficient Algorithms**: Optimized JDN conversion algorithms
|
||||
- **Memory Optimization**: Minimal memory allocation
|
||||
- **Concurrency Safety**: Stateless design supporting concurrent usage
|
||||
- **Resource Management**: Efficient resource utilization
|
||||
|
||||
### Functional Completeness
|
||||
- **Core Functions**: Complete implementation of all Persian calendar functions
|
||||
- **Formatting Support**: Comprehensive formatting capabilities
|
||||
- **Validation Features**: Complete validation and error handling
|
||||
- **Integration**: Seamless integration with Carbon library
|
||||
|
||||
### Reliability Assessment
|
||||
- **Authority Verification**: Verified against `Python` authority library
|
||||
- **Boundary Testing**: Comprehensive boundary condition testing
|
||||
- **Error Handling**: Robust error handling mechanisms
|
||||
- **Stability**: Stable operation across different scenarios
|
||||
|
||||
## Conclusion
|
||||
|
||||
The Persian calendar module demonstrates excellent quality and reliability:
|
||||
|
||||
### Strengths
|
||||
1. **High Accuracy**: 100% authority verification pass rate
|
||||
2. **Complete Coverage**: Comprehensive test coverage and validation
|
||||
3. **Excellent Performance**: Efficient algorithms and optimized operations
|
||||
4. **Robust Design**: Comprehensive error handling and boundary processing
|
||||
5. **Easy to Use**: Clean API design and complete documentation
|
||||
|
||||
This module provides a reliable technical foundation for Persian calendar processing, suitable for cultural, educational, financial, internationalization, and other application scenarios, and is an important component of the `Carbon` date and time library.
|
||||
9
vendor/github.com/dromara/carbon/v2/carbon.go
generated
vendored
9
vendor/github.com/dromara/carbon/v2/carbon.go
generated
vendored
@@ -61,3 +61,12 @@ func (c *Carbon) Copy() *Carbon {
|
||||
Error: c.Error,
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep sleeps for the specified duration like time.Sleep.
|
||||
func Sleep(d time.Duration) {
|
||||
if IsTestNow() && d > 0 {
|
||||
frozenNow.testNow = frozenNow.testNow.AddDuration(d.String())
|
||||
return
|
||||
}
|
||||
time.Sleep(d)
|
||||
}
|
||||
|
||||
113
vendor/github.com/dromara/carbon/v2/comparer.go
generated
vendored
113
vendor/github.com/dromara/carbon/v2/comparer.go
generated
vendored
@@ -4,7 +4,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// HasError reports whether has error.
|
||||
// HasError reports whether it has error.
|
||||
func (c *Carbon) HasError() bool {
|
||||
if c.IsNil() {
|
||||
return false
|
||||
@@ -12,12 +12,12 @@ func (c *Carbon) HasError() bool {
|
||||
return c.Error != nil
|
||||
}
|
||||
|
||||
// IsNil reports whether is nil pointer.
|
||||
// IsNil reports whether it is nil pointer.
|
||||
func (c *Carbon) IsNil() bool {
|
||||
return c == nil
|
||||
}
|
||||
|
||||
// IsEmpty reports whether is empty value.
|
||||
// IsEmpty reports whether it is empty value.
|
||||
func (c *Carbon) IsEmpty() bool {
|
||||
if c.IsNil() || c.HasError() {
|
||||
return false
|
||||
@@ -25,7 +25,7 @@ func (c *Carbon) IsEmpty() bool {
|
||||
return c.isEmpty
|
||||
}
|
||||
|
||||
// IsZero reports whether is a zero time(0001-01-01 00:00:00 +0000 UTC).
|
||||
// IsZero reports whether it is a zero time(0001-01-01 00:00:00 +0000 UTC).
|
||||
func (c *Carbon) IsZero() bool {
|
||||
if c.IsNil() || c.IsEmpty() || c.HasError() {
|
||||
return false
|
||||
@@ -33,7 +33,7 @@ func (c *Carbon) IsZero() bool {
|
||||
return c.StdTime().IsZero()
|
||||
}
|
||||
|
||||
// IsEpoch reports whether is a unix epoch time(1970-01-01 00:00:00 +0000 UTC).
|
||||
// IsEpoch reports whether it is a unix epoch time(1970-01-01 00:00:00 +0000 UTC).
|
||||
func (c *Carbon) IsEpoch() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -41,7 +41,7 @@ func (c *Carbon) IsEpoch() bool {
|
||||
return c.Eq(EpochValue())
|
||||
}
|
||||
|
||||
// IsValid reports whether is a valid time.
|
||||
// IsValid reports whether it is a valid time.
|
||||
func (c *Carbon) IsValid() bool {
|
||||
if !c.IsNil() && !c.HasError() && !c.IsEmpty() {
|
||||
return true
|
||||
@@ -49,12 +49,12 @@ func (c *Carbon) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsInvalid reports whether is an invalid time.
|
||||
// IsInvalid reports whether it is an invalid time.
|
||||
func (c *Carbon) IsInvalid() bool {
|
||||
return !c.IsValid()
|
||||
}
|
||||
|
||||
// IsDST reports whether is a daylight saving time.
|
||||
// IsDST reports whether it is a daylight saving time.
|
||||
func (c *Carbon) IsDST() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -62,7 +62,7 @@ func (c *Carbon) IsDST() bool {
|
||||
return c.StdTime().IsDST()
|
||||
}
|
||||
|
||||
// IsAM reports whether is before noon.
|
||||
// IsAM reports whether it is before noon.
|
||||
func (c *Carbon) IsAM() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -70,7 +70,7 @@ func (c *Carbon) IsAM() bool {
|
||||
return c.Format("a") == "am"
|
||||
}
|
||||
|
||||
// IsPM reports whether is after noon.
|
||||
// IsPM reports whether it is after noon.
|
||||
func (c *Carbon) IsPM() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -78,7 +78,7 @@ func (c *Carbon) IsPM() bool {
|
||||
return c.Format("a") == "pm"
|
||||
}
|
||||
|
||||
// IsLeapYear reports whether is a leap year.
|
||||
// IsLeapYear reports whether it is a leap year.
|
||||
func (c *Carbon) IsLeapYear() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -90,16 +90,18 @@ func (c *Carbon) IsLeapYear() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsLongYear reports whether is a long year, refer to https://en.wikipedia.org/wiki/ISO_8601#Week_dates.
|
||||
// IsLongYear reports whether it is a long year,
|
||||
//
|
||||
// refer to 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()
|
||||
_, w := time.Date(c.Year(), MaxMonth, MaxDay, MinHour, MinMinute, MinSecond, MinNanosecond, c.loc).ISOWeek()
|
||||
return w == WeeksPerLongYear
|
||||
}
|
||||
|
||||
// IsJanuary reports whether is January.
|
||||
// IsJanuary reports whether it is January.
|
||||
func (c *Carbon) IsJanuary() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -107,7 +109,7 @@ func (c *Carbon) IsJanuary() bool {
|
||||
return c.Month() == int(time.January)
|
||||
}
|
||||
|
||||
// IsFebruary reports whether is February.
|
||||
// IsFebruary reports whether it is February.
|
||||
func (c *Carbon) IsFebruary() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -115,7 +117,7 @@ func (c *Carbon) IsFebruary() bool {
|
||||
return c.Month() == int(time.February)
|
||||
}
|
||||
|
||||
// IsMarch reports whether is March.
|
||||
// IsMarch reports whether it is March.
|
||||
func (c *Carbon) IsMarch() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -123,7 +125,7 @@ func (c *Carbon) IsMarch() bool {
|
||||
return c.Month() == int(time.March)
|
||||
}
|
||||
|
||||
// IsApril reports whether is April.
|
||||
// IsApril reports whether it is April.
|
||||
func (c *Carbon) IsApril() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -131,7 +133,7 @@ func (c *Carbon) IsApril() bool {
|
||||
return c.Month() == int(time.April)
|
||||
}
|
||||
|
||||
// IsMay reports whether is May.
|
||||
// IsMay reports whether it is May.
|
||||
func (c *Carbon) IsMay() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -139,7 +141,7 @@ func (c *Carbon) IsMay() bool {
|
||||
return c.Month() == int(time.May)
|
||||
}
|
||||
|
||||
// IsJune reports whether is June.
|
||||
// IsJune reports whether it is June.
|
||||
func (c *Carbon) IsJune() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -147,7 +149,7 @@ func (c *Carbon) IsJune() bool {
|
||||
return c.Month() == int(time.June)
|
||||
}
|
||||
|
||||
// IsJuly reports whether is July.
|
||||
// IsJuly reports whether it is July.
|
||||
func (c *Carbon) IsJuly() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -155,7 +157,7 @@ func (c *Carbon) IsJuly() bool {
|
||||
return c.Month() == int(time.July)
|
||||
}
|
||||
|
||||
// IsAugust reports whether is August.
|
||||
// IsAugust reports whether it is August.
|
||||
func (c *Carbon) IsAugust() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -163,7 +165,7 @@ func (c *Carbon) IsAugust() bool {
|
||||
return c.Month() == int(time.August)
|
||||
}
|
||||
|
||||
// IsSeptember reports whether is September.
|
||||
// IsSeptember reports whether it is September.
|
||||
func (c *Carbon) IsSeptember() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -171,7 +173,7 @@ func (c *Carbon) IsSeptember() bool {
|
||||
return c.Month() == int(time.September)
|
||||
}
|
||||
|
||||
// IsOctober reports whether is October.
|
||||
// IsOctober reports whether it is October.
|
||||
func (c *Carbon) IsOctober() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -179,7 +181,7 @@ func (c *Carbon) IsOctober() bool {
|
||||
return c.Month() == int(time.October)
|
||||
}
|
||||
|
||||
// IsNovember reports whether is November.
|
||||
// IsNovember reports whether it is November.
|
||||
func (c *Carbon) IsNovember() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -187,7 +189,7 @@ func (c *Carbon) IsNovember() bool {
|
||||
return c.Month() == int(time.November)
|
||||
}
|
||||
|
||||
// IsDecember reports whether is December.
|
||||
// IsDecember reports whether it is December.
|
||||
func (c *Carbon) IsDecember() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -195,7 +197,7 @@ func (c *Carbon) IsDecember() bool {
|
||||
return c.Month() == int(time.December)
|
||||
}
|
||||
|
||||
// IsMonday reports whether is Monday.
|
||||
// IsMonday reports whether it is Monday.
|
||||
func (c *Carbon) IsMonday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -203,7 +205,7 @@ func (c *Carbon) IsMonday() bool {
|
||||
return c.StdTime().Weekday() == time.Monday
|
||||
}
|
||||
|
||||
// IsTuesday reports whether is Tuesday.
|
||||
// IsTuesday reports whether it is Tuesday.
|
||||
func (c *Carbon) IsTuesday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -211,7 +213,7 @@ func (c *Carbon) IsTuesday() bool {
|
||||
return c.StdTime().Weekday() == time.Tuesday
|
||||
}
|
||||
|
||||
// IsWednesday reports whether is Wednesday.
|
||||
// IsWednesday reports whether it is Wednesday.
|
||||
func (c *Carbon) IsWednesday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -219,7 +221,7 @@ func (c *Carbon) IsWednesday() bool {
|
||||
return c.StdTime().Weekday() == time.Wednesday
|
||||
}
|
||||
|
||||
// IsThursday reports whether is Thursday.
|
||||
// IsThursday reports whether it is Thursday.
|
||||
func (c *Carbon) IsThursday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -227,7 +229,7 @@ func (c *Carbon) IsThursday() bool {
|
||||
return c.StdTime().Weekday() == time.Thursday
|
||||
}
|
||||
|
||||
// IsFriday reports whether is Friday.
|
||||
// IsFriday reports whether it is Friday.
|
||||
func (c *Carbon) IsFriday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -235,7 +237,7 @@ func (c *Carbon) IsFriday() bool {
|
||||
return c.StdTime().Weekday() == time.Friday
|
||||
}
|
||||
|
||||
// IsSaturday reports whether is Saturday.
|
||||
// IsSaturday reports whether it is Saturday.
|
||||
func (c *Carbon) IsSaturday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -243,7 +245,7 @@ func (c *Carbon) IsSaturday() bool {
|
||||
return c.StdTime().Weekday() == time.Saturday
|
||||
}
|
||||
|
||||
// IsSunday reports whether is Sunday.
|
||||
// IsSunday reports whether it is Sunday.
|
||||
func (c *Carbon) IsSunday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -251,7 +253,7 @@ func (c *Carbon) IsSunday() bool {
|
||||
return c.StdTime().Weekday() == time.Sunday
|
||||
}
|
||||
|
||||
// IsWeekday reports whether is weekday.
|
||||
// IsWeekday reports whether it is weekday.
|
||||
func (c *Carbon) IsWeekday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -259,21 +261,21 @@ func (c *Carbon) IsWeekday() bool {
|
||||
return !c.IsWeekend()
|
||||
}
|
||||
|
||||
// IsWeekend reports whether is weekend.
|
||||
// IsWeekend reports whether it is weekend.
|
||||
func (c *Carbon) IsWeekend() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
d := c.StdTime().Weekday()
|
||||
for i := range c.weekendDays {
|
||||
if d == c.weekendDays[i] {
|
||||
for _, wd := range c.weekendDays {
|
||||
if d == wd {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// IsNow reports whether is now time.
|
||||
// IsNow reports whether it is now time.
|
||||
func (c *Carbon) IsNow() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -281,7 +283,7 @@ func (c *Carbon) IsNow() bool {
|
||||
return c.Timestamp() == Now().SetLocation(c.loc).Timestamp()
|
||||
}
|
||||
|
||||
// IsFuture reports whether is future time.
|
||||
// IsFuture reports whether it is future time.
|
||||
func (c *Carbon) IsFuture() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -292,7 +294,7 @@ func (c *Carbon) IsFuture() bool {
|
||||
return c.Timestamp() > Now().SetLocation(c.loc).Timestamp()
|
||||
}
|
||||
|
||||
// IsPast reports whether is past time.
|
||||
// IsPast reports whether it is past time.
|
||||
func (c *Carbon) IsPast() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -303,7 +305,7 @@ func (c *Carbon) IsPast() bool {
|
||||
return c.Timestamp() < Now().SetLocation(c.loc).Timestamp()
|
||||
}
|
||||
|
||||
// IsYesterday reports whether is yesterday.
|
||||
// IsYesterday reports whether it is yesterday.
|
||||
func (c *Carbon) IsYesterday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -311,7 +313,7 @@ func (c *Carbon) IsYesterday() bool {
|
||||
return c.ToDateString() == Yesterday().SetLocation(c.loc).ToDateString()
|
||||
}
|
||||
|
||||
// IsToday reports whether is today.
|
||||
// IsToday reports whether it is today.
|
||||
func (c *Carbon) IsToday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -319,7 +321,7 @@ func (c *Carbon) IsToday() bool {
|
||||
return c.ToDateString() == Now().SetLocation(c.loc).ToDateString()
|
||||
}
|
||||
|
||||
// IsTomorrow reports whether is tomorrow.
|
||||
// IsTomorrow reports whether it is tomorrow.
|
||||
func (c *Carbon) IsTomorrow() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
@@ -327,7 +329,7 @@ func (c *Carbon) IsTomorrow() bool {
|
||||
return c.ToDateString() == Tomorrow().SetLocation(c.loc).ToDateString()
|
||||
}
|
||||
|
||||
// IsSameCentury reports whether is same century.
|
||||
// IsSameCentury reports whether it is same century.
|
||||
func (c *Carbon) IsSameCentury(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -335,7 +337,7 @@ func (c *Carbon) IsSameCentury(t *Carbon) bool {
|
||||
return c.Century() == t.Century()
|
||||
}
|
||||
|
||||
// IsSameDecade reports whether is same decade.
|
||||
// IsSameDecade reports whether it is same decade.
|
||||
func (c *Carbon) IsSameDecade(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -343,7 +345,7 @@ func (c *Carbon) IsSameDecade(t *Carbon) bool {
|
||||
return c.Decade() == t.Decade()
|
||||
}
|
||||
|
||||
// IsSameYear reports whether is same year.
|
||||
// IsSameYear reports whether it is same year.
|
||||
func (c *Carbon) IsSameYear(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -351,7 +353,7 @@ func (c *Carbon) IsSameYear(t *Carbon) bool {
|
||||
return c.Year() == t.Year()
|
||||
}
|
||||
|
||||
// IsSameQuarter reports whether is same quarter.
|
||||
// IsSameQuarter reports whether it is same quarter.
|
||||
func (c *Carbon) IsSameQuarter(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -359,7 +361,7 @@ func (c *Carbon) IsSameQuarter(t *Carbon) bool {
|
||||
return c.Year() == t.Year() && c.Quarter() == t.Quarter()
|
||||
}
|
||||
|
||||
// IsSameMonth reports whether is same month.
|
||||
// IsSameMonth reports whether it is same month.
|
||||
func (c *Carbon) IsSameMonth(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -367,7 +369,7 @@ func (c *Carbon) IsSameMonth(t *Carbon) bool {
|
||||
return c.Format("Ym") == t.Format("Ym")
|
||||
}
|
||||
|
||||
// IsSameDay reports whether is same day.
|
||||
// IsSameDay reports whether it is same day.
|
||||
func (c *Carbon) IsSameDay(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -375,7 +377,7 @@ func (c *Carbon) IsSameDay(t *Carbon) bool {
|
||||
return c.Format("Ymd") == t.Format("Ymd")
|
||||
}
|
||||
|
||||
// IsSameHour reports whether is same hour.
|
||||
// IsSameHour reports whether it is same hour.
|
||||
func (c *Carbon) IsSameHour(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -383,7 +385,7 @@ func (c *Carbon) IsSameHour(t *Carbon) bool {
|
||||
return c.Format("YmdH") == t.Format("YmdH")
|
||||
}
|
||||
|
||||
// IsSameMinute reports whether is same minute.
|
||||
// IsSameMinute reports whether it is same minute.
|
||||
func (c *Carbon) IsSameMinute(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
@@ -391,13 +393,12 @@ func (c *Carbon) IsSameMinute(t *Carbon) bool {
|
||||
return c.Format("YmdHi") == t.Format("YmdHi")
|
||||
}
|
||||
|
||||
// IsSameSecond reports whether is same second.
|
||||
// IsSameSecond reports whether it is same second.
|
||||
func (c *Carbon) IsSameSecond(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("YmdHis") == t.Format("YmdHis")
|
||||
|
||||
}
|
||||
|
||||
// Compare compares by an operator.
|
||||
@@ -470,7 +471,7 @@ func (c *Carbon) Lte(t *Carbon) bool {
|
||||
return c.Lt(t) || c.Eq(t)
|
||||
}
|
||||
|
||||
// Between reports whether between two times, excluded the start and end time.
|
||||
// Between reports whether between two times, including the start and end time.
|
||||
func (c *Carbon) Between(start *Carbon, end *Carbon) bool {
|
||||
if start.Gt(end) {
|
||||
return false
|
||||
@@ -484,7 +485,7 @@ func (c *Carbon) Between(start *Carbon, end *Carbon) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// BetweenIncludedStart reports whether between two times, included the start time.
|
||||
// BetweenIncludedStart reports whether between two times, including the start time.
|
||||
func (c *Carbon) BetweenIncludedStart(start *Carbon, end *Carbon) bool {
|
||||
if start.Gt(end) {
|
||||
return false
|
||||
@@ -501,7 +502,7 @@ func (c *Carbon) BetweenIncludedStart(start *Carbon, end *Carbon) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// BetweenIncludedEnd reports whether between two times, included the end time.
|
||||
// BetweenIncludedEnd reports whether between two times, including the end time.
|
||||
func (c *Carbon) BetweenIncludedEnd(start *Carbon, end *Carbon) bool {
|
||||
if start.Gt(end) {
|
||||
return false
|
||||
@@ -518,7 +519,7 @@ func (c *Carbon) BetweenIncludedEnd(start *Carbon, end *Carbon) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// BetweenIncludedBoth reports whether between two times, included the start and end time.
|
||||
// BetweenIncludedBoth reports whether between two times, including the start and end time.
|
||||
func (c *Carbon) BetweenIncludedBoth(start *Carbon, end *Carbon) bool {
|
||||
if start.Gt(end) {
|
||||
return false
|
||||
|
||||
40
vendor/github.com/dromara/carbon/v2/constants.go
generated
vendored
40
vendor/github.com/dromara/carbon/v2/constants.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
// Version current version
|
||||
const Version = "2.6.7"
|
||||
const Version = "2.6.11"
|
||||
|
||||
// timezone constants
|
||||
const (
|
||||
@@ -88,6 +88,14 @@ const (
|
||||
December = time.December
|
||||
)
|
||||
|
||||
// season constants
|
||||
const (
|
||||
Spring = "Spring"
|
||||
Summer = "Summer"
|
||||
Autumn = "Autumn"
|
||||
Winter = "Winter"
|
||||
)
|
||||
|
||||
// constellation constants
|
||||
const (
|
||||
Aries = "Aries"
|
||||
@@ -115,14 +123,6 @@ const (
|
||||
Sunday = time.Sunday
|
||||
)
|
||||
|
||||
// season constants
|
||||
const (
|
||||
Spring = "Spring"
|
||||
Summer = "Summer"
|
||||
Autumn = "Autumn"
|
||||
Winter = "Winter"
|
||||
)
|
||||
|
||||
// number constants
|
||||
const (
|
||||
EpochYear = 1970
|
||||
@@ -148,6 +148,28 @@ const (
|
||||
SecondsPerMinute = 60
|
||||
)
|
||||
|
||||
// max constants
|
||||
const (
|
||||
MaxYear = 9999
|
||||
MaxMonth = 12
|
||||
MaxDay = 31
|
||||
MaxHour = 23
|
||||
MaxMinute = 59
|
||||
MaxSecond = 59
|
||||
MaxNanosecond = 999999999
|
||||
)
|
||||
|
||||
// min constants
|
||||
const (
|
||||
MinYear = 1
|
||||
MinMonth = 1
|
||||
MinDay = 1
|
||||
MinHour = 0
|
||||
MinMinute = 0
|
||||
MinSecond = 0
|
||||
MinNanosecond = 0
|
||||
)
|
||||
|
||||
// layout constants
|
||||
const (
|
||||
AtomLayout = RFC3339Layout
|
||||
|
||||
14
vendor/github.com/dromara/carbon/v2/creator.go
generated
vendored
14
vendor/github.com/dromara/carbon/v2/creator.go
generated
vendored
@@ -34,7 +34,7 @@ func CreateFromTimestamp(timestamp int64, timezone ...string) *Carbon {
|
||||
if loc, err = parseTimezone(tz); err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
return NewCarbon(time.Unix(timestamp, 0).In(loc))
|
||||
return NewCarbon(time.Unix(timestamp, MinNanosecond).In(loc))
|
||||
}
|
||||
|
||||
// CreateFromTimestampMilli creates a Carbon instance from a given timestamp with millisecond precision.
|
||||
@@ -93,7 +93,7 @@ func CreateFromTimestampNano(timestampNano int64, timezone ...string) *Carbon {
|
||||
|
||||
// CreateFromDateTime creates a Carbon instance from a given date and time.
|
||||
func CreateFromDateTime(year, month, day, hour, minute, second int, timezone ...string) *Carbon {
|
||||
return create(year, month, day, hour, minute, second, 0, timezone...)
|
||||
return create(year, month, day, hour, minute, second, MinNanosecond, timezone...)
|
||||
}
|
||||
|
||||
// CreateFromDateTimeMilli creates a Carbon instance from a given date, time and millisecond.
|
||||
@@ -113,28 +113,28 @@ func CreateFromDateTimeNano(year, month, day, hour, minute, second, nanosecond i
|
||||
|
||||
// CreateFromDate creates a Carbon instance from a given date.
|
||||
func CreateFromDate(year, month, day int, timezone ...string) *Carbon {
|
||||
return create(year, month, day, 0, 0, 0, 0, timezone...)
|
||||
return create(year, month, day, MinHour, MinMinute, MinSecond, MinNanosecond, timezone...)
|
||||
}
|
||||
|
||||
// CreateFromDateMilli creates a Carbon instance from a given date and millisecond.
|
||||
func CreateFromDateMilli(year, month, day, millisecond int, timezone ...string) *Carbon {
|
||||
return create(year, month, day, 0, 0, 0, millisecond*1e6, timezone...)
|
||||
return create(year, month, day, MinHour, MinMinute, MinSecond, millisecond*1e6, timezone...)
|
||||
}
|
||||
|
||||
// CreateFromDateMicro creates a Carbon instance from a given date and microsecond.
|
||||
func CreateFromDateMicro(year, month, day, microsecond int, timezone ...string) *Carbon {
|
||||
return create(year, month, day, 0, 0, 0, microsecond*1e3, timezone...)
|
||||
return create(year, month, day, MinHour, MinMinute, MinSecond, microsecond*1e3, timezone...)
|
||||
}
|
||||
|
||||
// CreateFromDateNano creates a Carbon instance from a given date and nanosecond.
|
||||
func CreateFromDateNano(year, month, day, nanosecond int, timezone ...string) *Carbon {
|
||||
return create(year, month, day, 0, 0, 0, nanosecond, timezone...)
|
||||
return create(year, month, day, MinHour, MinMinute, MinSecond, nanosecond, timezone...)
|
||||
}
|
||||
|
||||
// CreateFromTime creates a Carbon instance from a given time(year, month and day are taken from the current time).
|
||||
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...)
|
||||
return create(year, month, day, hour, minute, second, MinNanosecond, timezone...)
|
||||
}
|
||||
|
||||
// CreateFromTimeMilli creates a Carbon instance from a given time and millisecond(year, month and day are taken from the current time).
|
||||
|
||||
4
vendor/github.com/dromara/carbon/v2/difference.go
generated
vendored
4
vendor/github.com/dromara/carbon/v2/difference.go
generated
vendored
@@ -84,7 +84,7 @@ func (c *Carbon) DiffInWeeks(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (7 * 24 * 3600))))
|
||||
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (DaysPerWeek * HoursPerDay * SecondsPerHour))))
|
||||
}
|
||||
|
||||
// DiffAbsInWeeks gets the difference in weeks with absolute value.
|
||||
@@ -107,7 +107,7 @@ func (c *Carbon) DiffInDays(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (24 * 3600))))
|
||||
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (HoursPerDay * SecondsPerHour))))
|
||||
}
|
||||
|
||||
// DiffAbsInDays gets the difference in days with absolute value.
|
||||
|
||||
58
vendor/github.com/dromara/carbon/v2/extremum.go
generated
vendored
58
vendor/github.com/dromara/carbon/v2/extremum.go
generated
vendored
@@ -1,6 +1,8 @@
|
||||
package carbon
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
minDuration Duration = -1 << 63
|
||||
@@ -14,17 +16,17 @@ func ZeroValue() *Carbon {
|
||||
|
||||
// EpochValue returns the unix epoch value of Carbon instance.
|
||||
func EpochValue() *Carbon {
|
||||
return NewCarbon(time.Date(EpochYear, time.January, 1, 0, 0, 0, 0, time.UTC))
|
||||
return NewCarbon(time.Date(EpochYear, time.January, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond, time.UTC))
|
||||
}
|
||||
|
||||
// MaxValue returns the maximum value of Carbon instance.
|
||||
func MaxValue() *Carbon {
|
||||
return NewCarbon(time.Date(9999, time.December, 31, 23, 59, 59, 999999999, time.UTC))
|
||||
return NewCarbon(time.Date(MaxYear, time.December, MaxDay, MaxHour, MaxMinute, MaxSecond, MaxNanosecond, time.UTC))
|
||||
}
|
||||
|
||||
// MinValue returns the minimum value of Carbon instance.
|
||||
func MinValue() *Carbon {
|
||||
return NewCarbon(time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC))
|
||||
return NewCarbon(time.Date(MinYear, time.January, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond, time.UTC))
|
||||
}
|
||||
|
||||
// MaxDuration returns the maximum value of duration instance.
|
||||
@@ -46,12 +48,12 @@ func Max(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
|
||||
if len(c2) == 0 {
|
||||
return
|
||||
}
|
||||
for i := range c2 {
|
||||
if c2[i].IsInvalid() {
|
||||
return c2[i]
|
||||
for _, carbon := range c2 {
|
||||
if carbon.IsInvalid() {
|
||||
return carbon
|
||||
}
|
||||
if c2[i].Gte(c) {
|
||||
c = c2[i]
|
||||
if carbon.Gte(c) {
|
||||
c = carbon
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -66,12 +68,12 @@ func Min(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
|
||||
if len(c2) == 0 {
|
||||
return
|
||||
}
|
||||
for i := range c2 {
|
||||
if c2[i].IsInvalid() {
|
||||
return c2[i]
|
||||
for _, carbon := range c2 {
|
||||
if carbon.IsInvalid() {
|
||||
return carbon
|
||||
}
|
||||
if c2[i].Lte(c) {
|
||||
c = c2[i]
|
||||
if carbon.Lte(c) {
|
||||
c = carbon
|
||||
}
|
||||
}
|
||||
return
|
||||
@@ -88,16 +90,12 @@ func (c *Carbon) Closest(c1 *Carbon, c2 ...*Carbon) *Carbon {
|
||||
if len(c2) == 0 {
|
||||
return c1
|
||||
}
|
||||
args := append([]*Carbon{c1}, c2...)
|
||||
for i := range args {
|
||||
if args[i].IsInvalid() {
|
||||
return args[i]
|
||||
}
|
||||
}
|
||||
closest := args[0]
|
||||
closest := c1
|
||||
minDiff := c.DiffAbsInSeconds(closest)
|
||||
for i := range args[1:] {
|
||||
arg := args[1:][i]
|
||||
for _, arg := range c2 {
|
||||
if arg.IsInvalid() {
|
||||
return arg
|
||||
}
|
||||
diff := c.DiffAbsInSeconds(arg)
|
||||
if diff < minDiff {
|
||||
minDiff = diff
|
||||
@@ -118,16 +116,12 @@ func (c *Carbon) Farthest(c1 *Carbon, c2 ...*Carbon) *Carbon {
|
||||
if len(c2) == 0 {
|
||||
return c1
|
||||
}
|
||||
args := append([]*Carbon{c1}, c2...)
|
||||
for i := range args {
|
||||
if args[i].IsInvalid() {
|
||||
return args[i]
|
||||
}
|
||||
}
|
||||
farthest := args[0]
|
||||
farthest := c1
|
||||
maxDiff := c.DiffAbsInSeconds(farthest)
|
||||
for i := range args[1:] {
|
||||
arg := args[1:][i]
|
||||
for _, arg := range c2 {
|
||||
if arg.IsInvalid() {
|
||||
return arg
|
||||
}
|
||||
diff := c.DiffAbsInSeconds(arg)
|
||||
if diff > maxDiff {
|
||||
maxDiff = diff
|
||||
|
||||
38
vendor/github.com/dromara/carbon/v2/frozen.go
generated
vendored
38
vendor/github.com/dromara/carbon/v2/frozen.go
generated
vendored
@@ -1,46 +1,42 @@
|
||||
package carbon
|
||||
|
||||
import "sync"
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
// FrozenNow defines a FrozenNow struct.
|
||||
type FrozenNow struct {
|
||||
isFrozen bool
|
||||
isFrozen int32
|
||||
testNow *Carbon
|
||||
rw *sync.RWMutex
|
||||
rw sync.RWMutex
|
||||
}
|
||||
|
||||
var frozenNow = &FrozenNow{
|
||||
rw: new(sync.RWMutex),
|
||||
}
|
||||
var frozenNow = &FrozenNow{}
|
||||
|
||||
// SetTestNow sets a test Carbon instance for now.
|
||||
func SetTestNow(c *Carbon) {
|
||||
if c == nil {
|
||||
return
|
||||
}
|
||||
|
||||
frozenNow.rw.Lock()
|
||||
defer frozenNow.rw.Unlock()
|
||||
|
||||
frozenNow.isFrozen = true
|
||||
frozenNow.testNow = c
|
||||
}
|
||||
frozenNow.rw.Unlock()
|
||||
|
||||
// CleanTestNow clears the test Carbon instance for now.
|
||||
//
|
||||
// Deprecated: it will be removed in the future, use "ClearTestNow" instead.
|
||||
func CleanTestNow() {
|
||||
ClearTestNow()
|
||||
atomic.StoreInt32(&frozenNow.isFrozen, 1)
|
||||
}
|
||||
|
||||
// ClearTestNow clears the test Carbon instance for now.
|
||||
func ClearTestNow() {
|
||||
frozenNow.rw.Lock()
|
||||
defer frozenNow.rw.Unlock()
|
||||
frozenNow.testNow = nil
|
||||
frozenNow.rw.Unlock()
|
||||
|
||||
frozenNow.isFrozen = false
|
||||
atomic.StoreInt32(&frozenNow.isFrozen, 0)
|
||||
}
|
||||
|
||||
// IsTestNow reports whether is testing time.
|
||||
func IsTestNow() bool {
|
||||
frozenNow.rw.Lock()
|
||||
defer frozenNow.rw.Unlock()
|
||||
|
||||
return frozenNow.isFrozen
|
||||
return atomic.LoadInt32(&frozenNow.isFrozen) == 1
|
||||
}
|
||||
|
||||
6
vendor/github.com/dromara/carbon/v2/getter.go
generated
vendored
6
vendor/github.com/dromara/carbon/v2/getter.go
generated
vendored
@@ -66,7 +66,9 @@ func (c *Carbon) DayOfWeek() int {
|
||||
return (int(c.StdTime().Weekday())+DaysPerWeek-int(c.weekStartsAt))%DaysPerWeek + 1
|
||||
}
|
||||
|
||||
// WeekOfYear gets week of year like 1, refer to https://en.wikipedia.org/wiki/ISO_8601#Week_dates.
|
||||
// WeekOfYear gets week of year like 1.
|
||||
//
|
||||
// refer to https://en.wikipedia.org/wiki/ISO_8601#Week_dates.
|
||||
func (c *Carbon) WeekOfYear() int {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
@@ -384,7 +386,7 @@ func (c *Carbon) WeekEndsAt() Weekday {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return Weekday((int(c.weekStartsAt) + DaysPerWeek - 1) % 7)
|
||||
return Weekday((int(c.weekStartsAt) + DaysPerWeek - 1) % DaysPerWeek)
|
||||
}
|
||||
|
||||
// CurrentLayout returns the layout used for parsing the time string.
|
||||
|
||||
5
vendor/github.com/dromara/carbon/v2/helper.go
generated
vendored
5
vendor/github.com/dromara/carbon/v2/helper.go
generated
vendored
@@ -138,8 +138,5 @@ func parseTimestamp(timestamp string) (ts int64, err error) {
|
||||
|
||||
// gets absolute value.
|
||||
func getAbsValue(value int64) int64 {
|
||||
if value < 0 {
|
||||
return -value
|
||||
}
|
||||
return value
|
||||
return (value ^ (value >> 63)) - (value >> 63)
|
||||
}
|
||||
|
||||
5
vendor/github.com/dromara/carbon/v2/interfaces.go
generated
vendored
5
vendor/github.com/dromara/carbon/v2/interfaces.go
generated
vendored
@@ -1,10 +1,5 @@
|
||||
package carbon
|
||||
|
||||
// DataTyper defines a DataTyper interface
|
||||
type DataTyper interface {
|
||||
DataType() string
|
||||
}
|
||||
|
||||
// LayoutTyper defines a LayoutTyper interface
|
||||
type LayoutTyper interface {
|
||||
~string
|
||||
|
||||
49
vendor/github.com/dromara/carbon/v2/language.go
generated
vendored
49
vendor/github.com/dromara/carbon/v2/language.go
generated
vendored
@@ -52,9 +52,13 @@ func (lang *Language) Copy() *Language {
|
||||
if lang.resources == nil {
|
||||
return newLang
|
||||
}
|
||||
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
newLang.resources = make(map[string]string)
|
||||
for i := range lang.resources {
|
||||
newLang.resources[i] = lang.resources[i]
|
||||
for k, v := range lang.resources {
|
||||
newLang.resources[k] = v
|
||||
}
|
||||
return newLang
|
||||
}
|
||||
@@ -69,20 +73,21 @@ func (lang *Language) SetLocale(locale string) *Language {
|
||||
return lang
|
||||
}
|
||||
|
||||
fileName := fmt.Sprintf("%s/%s.json", lang.dir, locale)
|
||||
bs, err := fs.ReadFile(fileName)
|
||||
if err != nil {
|
||||
lang.Error = fmt.Errorf("%w: %w", ErrNotExistLocale(fileName), err)
|
||||
return lang
|
||||
}
|
||||
|
||||
var resources map[string]string
|
||||
_ = json.Unmarshal(bs, &resources)
|
||||
|
||||
lang.rw.Lock()
|
||||
defer lang.rw.Unlock()
|
||||
|
||||
lang.locale = locale
|
||||
fileName := fmt.Sprintf("%s/%s.json", lang.dir, locale)
|
||||
var (
|
||||
bs []byte
|
||||
err error
|
||||
)
|
||||
if bs, err = fs.ReadFile(fileName); err != nil {
|
||||
lang.Error = fmt.Errorf("%w: %w", ErrNotExistLocale(fileName), err)
|
||||
return lang
|
||||
}
|
||||
_ = json.Unmarshal(bs, &lang.resources)
|
||||
lang.resources = resources
|
||||
return lang
|
||||
}
|
||||
|
||||
@@ -99,20 +104,13 @@ func (lang *Language) SetResources(resources map[string]string) *Language {
|
||||
lang.rw.Lock()
|
||||
defer lang.rw.Unlock()
|
||||
|
||||
if len(lang.resources) == 0 {
|
||||
lang.resources = resources
|
||||
}
|
||||
|
||||
for i := range resources {
|
||||
if !slices.Contains(validResourcesKey, i) {
|
||||
for k, v := range resources {
|
||||
if !slices.Contains(validResourcesKey, k) {
|
||||
lang.Error = ErrInvalidResourcesError(resources)
|
||||
return lang
|
||||
}
|
||||
if _, ok := lang.resources[i]; ok {
|
||||
lang.resources[i] = resources[i]
|
||||
}
|
||||
lang.resources[k] = v
|
||||
}
|
||||
|
||||
return lang
|
||||
}
|
||||
|
||||
@@ -123,14 +121,15 @@ func (lang *Language) translate(unit string, value int64) string {
|
||||
}
|
||||
|
||||
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], "|")
|
||||
resources := lang.resources
|
||||
defer lang.rw.Unlock()
|
||||
|
||||
slice := strings.Split(resources[unit], "|")
|
||||
number := getAbsValue(value)
|
||||
if len(slice) == 1 {
|
||||
return strings.Replace(slice[0], "%d", strconv.FormatInt(value, 10), 1)
|
||||
|
||||
59
vendor/github.com/dromara/carbon/v2/parser.go
generated
vendored
59
vendor/github.com/dromara/carbon/v2/parser.go
generated
vendored
@@ -35,10 +35,10 @@ func Parse(value string, timezone ...string) *Carbon {
|
||||
return Tomorrow().SetLocation(loc)
|
||||
}
|
||||
c := NewCarbon().SetLocation(loc)
|
||||
for i := range defaultLayouts {
|
||||
if tt, err = time.ParseInLocation(defaultLayouts[i], value, loc); err == nil {
|
||||
for _, layout := range defaultLayouts {
|
||||
if tt, err = time.ParseInLocation(layout, value, loc); err == nil {
|
||||
c.time = tt
|
||||
c.currentLayout = defaultLayouts[i]
|
||||
c.currentLayout = layout
|
||||
return c
|
||||
}
|
||||
}
|
||||
@@ -48,8 +48,7 @@ func Parse(value string, timezone ...string) *Carbon {
|
||||
|
||||
// ParseByLayout parses a time string as a Carbon instance by a confirmed layout.
|
||||
//
|
||||
// Note: it will not support parsing timestamp string in the future,
|
||||
// use "CreateFromTimestamp" or "CreateFromTimestampXXX" instead
|
||||
// Note: it doesn't support parsing timestamp string.
|
||||
func ParseByLayout(value, layout string, timezone ...string) *Carbon {
|
||||
if value == "" {
|
||||
return &Carbon{isEmpty: true}
|
||||
@@ -58,7 +57,6 @@ func ParseByLayout(value, layout string, timezone ...string) *Carbon {
|
||||
return &Carbon{Error: ErrEmptyLayout()}
|
||||
}
|
||||
var (
|
||||
ts int64
|
||||
tz string
|
||||
tt StdTime
|
||||
loc *Location
|
||||
@@ -73,31 +71,6 @@ func ParseByLayout(value, layout string, timezone ...string) *Carbon {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
|
||||
// timestamp layouts
|
||||
switch layout {
|
||||
case TimestampLayout:
|
||||
if ts, err = parseTimestamp(value); err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
return CreateFromTimestamp(ts).SetLocation(loc)
|
||||
case TimestampMilliLayout:
|
||||
if ts, err = parseTimestamp(value); err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
return CreateFromTimestampMilli(ts).SetLocation(loc)
|
||||
case TimestampMicroLayout:
|
||||
if ts, err = parseTimestamp(value); err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
return CreateFromTimestampMicro(ts).SetLocation(loc)
|
||||
case TimestampNanoLayout:
|
||||
if ts, err = parseTimestamp(value); err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
return CreateFromTimestampNano(ts).SetLocation(loc)
|
||||
}
|
||||
|
||||
// other layouts
|
||||
if tt, err = time.ParseInLocation(layout, value, loc); err != nil {
|
||||
return &Carbon{Error: fmt.Errorf("%w: %w", ErrMismatchedLayout(value, layout), err)}
|
||||
}
|
||||
@@ -151,10 +124,10 @@ func ParseByLayouts(value string, layouts []string, timezone ...string) *Carbon
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
c := NewCarbon().SetLocation(loc)
|
||||
for i := range layouts {
|
||||
if tt, err = time.ParseInLocation(layouts[i], value, loc); err == nil {
|
||||
for _, layout := range layouts {
|
||||
if tt, err = time.ParseInLocation(layout, value, loc); err == nil {
|
||||
c.time = tt
|
||||
c.currentLayout = layouts[i]
|
||||
c.currentLayout = layout
|
||||
return c
|
||||
}
|
||||
}
|
||||
@@ -185,22 +158,8 @@ func ParseByFormats(value string, formats []string, timezone ...string) *Carbon
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
var layouts []string
|
||||
for i := range formats {
|
||||
layouts = append(layouts, format2layout(formats[i]))
|
||||
for _, v := range formats {
|
||||
layouts = append(layouts, format2layout(v))
|
||||
}
|
||||
return ParseByLayouts(value, layouts, tz)
|
||||
}
|
||||
|
||||
// ParseWithLayouts parses a time string as a Carbon instance by multiple fuzzy layouts.
|
||||
//
|
||||
// Deprecated: it will be removed in the future, use "ParseByLayouts" instead.
|
||||
func ParseWithLayouts(value string, layouts []string, timezone ...string) *Carbon {
|
||||
return ParseByLayouts(value, layouts, timezone...)
|
||||
}
|
||||
|
||||
// ParseWithFormats parses a time string as a Carbon instance by multiple fuzzy formats.
|
||||
//
|
||||
// Deprecated: it will be removed in the future, use "ParseByFormats" instead.
|
||||
func ParseWithFormats(value string, formats []string, timezone ...string) *Carbon {
|
||||
return ParseByFormats(value, formats, timezone...)
|
||||
}
|
||||
|
||||
69
vendor/github.com/dromara/carbon/v2/season.go
generated
vendored
69
vendor/github.com/dromara/carbon/v2/season.go
generated
vendored
@@ -4,21 +4,20 @@ 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
|
||||
var seasons = map[int]int{
|
||||
// month: index
|
||||
1: 3, // winter
|
||||
2: 3, // winter
|
||||
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
|
||||
}
|
||||
|
||||
// Season gets season name according to the meteorological division method like "Spring", i18n is supported.
|
||||
@@ -26,14 +25,6 @@ func (c *Carbon) Season() string {
|
||||
if c.IsInvalid() {
|
||||
return ""
|
||||
}
|
||||
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()
|
||||
@@ -41,7 +32,7 @@ func (c *Carbon) Season() string {
|
||||
if resources, ok := c.lang.resources["seasons"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == QuartersPerYear {
|
||||
return slice[index]
|
||||
return slice[seasons[c.Month()]]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
@@ -54,9 +45,9 @@ func (c *Carbon) StartOfSeason() *Carbon {
|
||||
}
|
||||
year, month, _ := c.Date()
|
||||
if month == 1 || month == 2 {
|
||||
return c.create(year-1, 12, 1, 0, 0, 0, 0)
|
||||
return c.create(year-1, MaxMonth, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
return c.create(year, month/3*3, 1, 0, 0, 0, 0)
|
||||
return c.create(year, month/3*3, MinDay, MinHour, MinMinute, MinSecond, MinNanosecond)
|
||||
}
|
||||
|
||||
// EndOfSeason returns a Carbon instance for end of the season.
|
||||
@@ -66,12 +57,12 @@ func (c *Carbon) EndOfSeason() *Carbon {
|
||||
}
|
||||
year, month, _ := c.Date()
|
||||
if month == 1 || month == 2 {
|
||||
return c.create(year, 3, 0, 23, 59, 59, 999999999)
|
||||
return c.create(year, 3, 0, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
if month == 12 {
|
||||
return c.create(year+1, 3, 0, 23, 59, 59, 999999999)
|
||||
return c.create(year+1, 3, 0, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
return c.create(year, month/3*3+3, 0, 23, 59, 59, 999999999)
|
||||
return c.create(year, month/3*3+3, 0, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
// IsSpring reports whether is spring.
|
||||
@@ -80,10 +71,7 @@ func (c *Carbon) IsSpring() bool {
|
||||
return false
|
||||
}
|
||||
month := c.Month()
|
||||
if month == 3 || month == 4 || month == 5 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return month == 3 || month == 4 || month == 5
|
||||
}
|
||||
|
||||
// IsSummer reports whether is summer.
|
||||
@@ -92,10 +80,7 @@ func (c *Carbon) IsSummer() bool {
|
||||
return false
|
||||
}
|
||||
month := c.Month()
|
||||
if month == 6 || month == 7 || month == 8 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return month == 6 || month == 7 || month == 8
|
||||
}
|
||||
|
||||
// IsAutumn reports whether is autumn.
|
||||
@@ -104,10 +89,7 @@ func (c *Carbon) IsAutumn() bool {
|
||||
return false
|
||||
}
|
||||
month := c.Month()
|
||||
if month == 9 || month == 10 || month == 11 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return month == 9 || month == 10 || month == 11
|
||||
}
|
||||
|
||||
// IsWinter reports whether is winter.
|
||||
@@ -116,8 +98,5 @@ func (c *Carbon) IsWinter() bool {
|
||||
return false
|
||||
}
|
||||
month := c.Month()
|
||||
if month == 12 || month == 1 || month == 2 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return month == 1 || month == 2 || month == 12
|
||||
}
|
||||
|
||||
420
vendor/github.com/dromara/carbon/v2/test_report.cn.md
generated
vendored
Normal file
420
vendor/github.com/dromara/carbon/v2/test_report.cn.md
generated
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
# Carbon 性能测试分析报告
|
||||
|
||||
## 概述
|
||||
|
||||
本报告对 Carbon 日期时间库进行了全面的性能测试分析,涵盖了核心功能模块、历法转换、类型操作等各个方面的性能表现。测试采用 Go 标准基准测试框架,包含顺序执行、并发执行和并行执行三种模式。
|
||||
|
||||
## 测试环境
|
||||
|
||||
- **操作系统**: macOS 14.5.0
|
||||
- **Go 版本**: 1.21+
|
||||
- **CPU**: Apple Silicon M1/M2
|
||||
- **测试框架**: Go testing package
|
||||
- **测试模式**: sequential(顺序)、concurrent(并发)、parallel(并行)
|
||||
|
||||
## 核心功能模块性能分析
|
||||
|
||||
### Carbon 实例创建性能
|
||||
|
||||
#### NewCarbon 性能测试
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~55ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- Carbon 实例创建性能优异,单次操作耗时约 50-60 纳秒
|
||||
- 无内存分配开销,内存效率极高
|
||||
- 并发和并行模式下性能稳定,无明显性能衰减
|
||||
|
||||
#### Copy 操作性能测试
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~120ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~140ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~130ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- Copy 操作性能良好,单次操作耗时约 120-140 纳秒
|
||||
- 每次操作分配 48 字节内存,内存开销可控
|
||||
- 并发安全性良好,性能稳定
|
||||
|
||||
#### Sleep 操作性能测试
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**不同时间间隔性能对比**:
|
||||
|
||||
| 时间间隔 | 平均耗时 | 性能评级 |
|
||||
|---------|---------|---------|
|
||||
| 1ns | ~50ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1μs | ~60ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1ms | ~80ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1s | ~100ns | ⭐⭐⭐⭐ |
|
||||
| 1min | ~120ns | ⭐⭐⭐⭐ |
|
||||
| 1hour | ~150ns | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- Sleep 操作性能优秀,无内存分配开销
|
||||
- 时间间隔越大,操作耗时略有增加,但整体性能稳定
|
||||
- 并发安全性良好
|
||||
|
||||
## 类型系统性能分析
|
||||
|
||||
### Carbon 类型操作性能
|
||||
|
||||
#### Scan 操作性能
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~90ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~85ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### Value 操作性能
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~70ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~75ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON 序列化性能
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~850ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~820ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON 反序列化性能
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~1200ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~1300ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~1250ns | 512 B/op | ⭐⭐⭐ |
|
||||
|
||||
#### String 转换性能
|
||||
|
||||
| 测试模式 | 操作次数 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|---------|
|
||||
| Sequential | 10,000 | ~150ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~160ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~155ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 基础类型操作(Scan、Value)性能优异,无内存分配
|
||||
- JSON 序列化性能良好,反序列化相对较慢但可接受
|
||||
- String 转换性能稳定,内存开销小
|
||||
|
||||
### 内置类型性能对比
|
||||
|
||||
#### 内置类型 vs Carbon 类型性能对比
|
||||
|
||||
| 操作类型 | 内置类型耗时 | Carbon类型耗时 | 性能差异 | 推荐使用 |
|
||||
|---------|-------------|---------------|---------|---------|
|
||||
| Scan | ~60ns | ~80ns | +33% | 内置类型 |
|
||||
| Value | ~50ns | ~70ns | +40% | 内置类型 |
|
||||
| MarshalJSON | ~600ns | ~800ns | +33% | 内置类型 |
|
||||
| UnmarshalJSON | ~1000ns | ~1200ns | +20% | 内置类型 |
|
||||
| String | ~100ns | ~150ns | +50% | 内置类型 |
|
||||
|
||||
**分析结论**:
|
||||
- 内置类型在性能上优于 Carbon 类型
|
||||
- 对于高性能场景,建议使用内置类型
|
||||
- Carbon 类型提供更多功能,适合需要扩展功能的场景
|
||||
|
||||
## 历法转换性能分析
|
||||
|
||||
### 希伯来历性能测试
|
||||
|
||||
#### 公历转希伯来历性能
|
||||
|
||||
| 测试日期 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| 2024-01-01 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-03-20 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-06-21 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-09-22 | ~230ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-12-21 | ~240ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### 希伯来历转公历性能
|
||||
|
||||
| 测试日期 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| 5784-01-01 | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-06-15 | ~190ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-12-29 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 5785-01-01 | ~185ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5785-12-30 | ~195ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### 希伯来历基础操作性能
|
||||
|
||||
| 操作类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| Year() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Month() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Day() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| String() | ~50ns | 16 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| IsLeapYear() | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToMonthString() | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToWeekString() | ~120ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### 希伯来历算法性能
|
||||
|
||||
| 算法类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| gregorian2jdn | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| hebrew2jdn | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2hebrew | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2gregorian | ~160ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 希伯来历转换性能优秀,单次操作耗时 180-240 纳秒
|
||||
- 基础操作(年、月、日)性能极佳,接近零开销
|
||||
- 算法实现高效,无内存分配开销
|
||||
- 字符串操作性能良好,内存开销可控
|
||||
|
||||
### 波斯历性能测试
|
||||
|
||||
#### 波斯历转换性能
|
||||
|
||||
| 操作类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| FromStdTime | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 基础操作 | ~10ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 波斯历转换性能良好,单次操作耗时 250-300 纳秒
|
||||
- 算法实现高效,无内存分配开销
|
||||
- 基础操作性能优异
|
||||
|
||||
### 儒略历性能测试
|
||||
|
||||
#### 儒略历转换性能
|
||||
|
||||
| 操作类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| FromStdTime | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 基础操作 | ~8ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 儒略历转换性能优秀,单次操作耗时 200-250 纳秒
|
||||
- 算法实现高效,无内存分配开销
|
||||
- 基础操作性能极佳
|
||||
|
||||
### 农历性能测试
|
||||
|
||||
#### 农历转换性能
|
||||
|
||||
| 操作类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| FromStdTime | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~350ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 基础操作 | ~12ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 农历转换性能良好,单次操作耗时 300-350 纳秒
|
||||
- 算法相对复杂,但性能仍可接受
|
||||
- 基础操作性能优异
|
||||
|
||||
## 高级功能性能分析
|
||||
|
||||
### 输出器性能测试
|
||||
|
||||
#### 格式化输出性能
|
||||
|
||||
| 格式类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| 标准格式 | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 自定义格式 | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 复杂格式 | ~500ns | 128 B/op | ⭐⭐⭐ |
|
||||
| JSON格式 | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### 多语言输出性能
|
||||
|
||||
| 语言类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| 中文 | ~150ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| 英文 | ~120ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 日文 | ~180ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 韩文 | ~160ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 标准格式输出性能优异
|
||||
- 自定义格式性能良好
|
||||
- 多语言支持性能稳定
|
||||
- 复杂格式相对较慢,但仍在可接受范围内
|
||||
|
||||
### 解析器性能测试
|
||||
|
||||
#### 字符串解析性能
|
||||
|
||||
| 解析类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| 标准格式 | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 自定义格式 | ~400ns | 128 B/op | ⭐⭐⭐ |
|
||||
| 复杂格式 | ~800ns | 256 B/op | ⭐⭐⭐ |
|
||||
| 错误格式 | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 标准格式解析性能良好
|
||||
- 自定义格式解析相对较慢
|
||||
- 错误处理性能优异
|
||||
|
||||
### 比较器性能测试
|
||||
|
||||
#### 日期比较性能
|
||||
|
||||
| 比较类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| 相等比较 | ~20ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 大小比较 | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 范围比较 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 复杂比较 | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 比较操作性能极佳,接近零开销
|
||||
- 无内存分配,效率极高
|
||||
- 适合高频比较场景
|
||||
|
||||
### 旅行者功能性能测试
|
||||
|
||||
#### 时间旅行性能
|
||||
|
||||
| 操作类型 | 平均耗时 | 内存分配 | 性能评级 |
|
||||
|---------|---------|---------|---------|
|
||||
| AddYear | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMonth | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddDay | ~40ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddHour | ~35ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMinute | ~30ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddSecond | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 时间旅行功能性能优异
|
||||
- 所有操作都无内存分配开销
|
||||
- 适合频繁的时间计算场景
|
||||
|
||||
## 内存使用分析
|
||||
|
||||
### 内存分配统计
|
||||
|
||||
| 模块类型 | 平均内存分配 | 最大内存分配 | 内存效率评级 |
|
||||
|---------|-------------|-------------|-------------|
|
||||
| 核心操作 | 0-48 B/op | 64 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 类型转换 | 0-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| 历法转换 | 0 B/op | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 格式化输出 | 32-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| 字符串解析 | 64-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- 历法转换模块内存效率最高,零分配
|
||||
- 核心操作内存效率优秀
|
||||
- 字符串操作内存开销可控
|
||||
- 整体内存使用效率良好
|
||||
|
||||
## 并发性能分析
|
||||
|
||||
### 并发安全性测试
|
||||
|
||||
| 测试场景 | 性能衰减 | 内存泄漏 | 并发安全性评级 |
|
||||
|---------|---------|---------|---------------|
|
||||
| 高并发创建 | <5% | 无 | ⭐⭐⭐⭐⭐ |
|
||||
| 高并发转换 | <10% | 无 | ⭐⭐⭐⭐⭐ |
|
||||
| 高并发比较 | <3% | 无 | ⭐⭐⭐⭐⭐ |
|
||||
| 高并发格式化 | <15% | 无 | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析结论**:
|
||||
- Carbon 库具有良好的并发安全性
|
||||
- 高并发场景下性能衰减较小
|
||||
- 无内存泄漏问题
|
||||
- 适合高并发应用场景
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 性能优化策略
|
||||
|
||||
#### 代码层面优化
|
||||
|
||||
**对象复用**:
|
||||
- 对于频繁使用的 Carbon 实例,建议复用而不是重新创建
|
||||
- 使用对象池模式减少内存分配
|
||||
|
||||
**缓存策略**:
|
||||
- 对于复杂的历法计算,可以添加结果缓存
|
||||
- 字符串格式化结果可以缓存
|
||||
|
||||
**算法优化**:
|
||||
- 农历算法相对复杂,可以考虑进一步优化
|
||||
- JSON 序列化可以使用更高效的实现
|
||||
|
||||
#### 使用建议
|
||||
|
||||
**高性能场景**:
|
||||
- 使用内置类型而非 Carbon 类型
|
||||
- 避免频繁的字符串格式化
|
||||
- 复用 Carbon 实例
|
||||
|
||||
**一般场景**:
|
||||
- Carbon 类型提供更好的功能支持
|
||||
- 格式化输出性能足够满足需求
|
||||
|
||||
**历法转换场景**:
|
||||
- 希伯来历和儒略历性能最佳
|
||||
- 农历转换相对较慢,但仍在可接受范围
|
||||
|
||||
## 总结
|
||||
|
||||
### 性能评估
|
||||
|
||||
| 性能维度 | 评分 | 评价 |
|
||||
|---------|------|------|
|
||||
| 执行效率 | ⭐⭐⭐⭐⭐ | 核心操作性能优异 |
|
||||
| 内存效率 | ⭐⭐⭐⭐⭐ | 内存使用效率高 |
|
||||
| 并发性能 | ⭐⭐⭐⭐⭐ | 并发安全性良好 |
|
||||
| 功能完整性 | ⭐⭐⭐⭐⭐ | 功能丰富完整 |
|
||||
| 易用性 | ⭐⭐⭐⭐⭐ | API 设计友好 |
|
||||
|
||||
### 性能亮点
|
||||
|
||||
**极佳的基础性能**:
|
||||
核心操作耗时在 50-200 纳秒范围内
|
||||
|
||||
**零内存分配**:
|
||||
历法转换和基础操作无内存分配开销
|
||||
|
||||
**优秀的并发性能**:
|
||||
高并发场景下性能衰减小于 15%
|
||||
|
||||
**丰富的功能支持**:
|
||||
支持多种历法和格式化选项
|
||||
|
||||
**良好的扩展性**:
|
||||
支持自定义格式和类型
|
||||
|
||||
### 改进方向
|
||||
|
||||
**农历算法优化**:可以进一步优化农历转换算法
|
||||
|
||||
**JSON 性能提升**:可以考虑使用更高效的 JSON 序列化库
|
||||
|
||||
**缓存机制**:为复杂计算添加结果缓存
|
||||
|
||||
**内存池**:为高频操作实现对象池
|
||||
|
||||
Carbon 项目整体性能表现优秀,特别是在核心功能和历法转换方面表现突出,是一个高性能、功能完整的日期时间处理库。
|
||||
|
||||
415
vendor/github.com/dromara/carbon/v2/test_report.en.md
generated
vendored
Normal file
415
vendor/github.com/dromara/carbon/v2/test_report.en.md
generated
vendored
Normal file
@@ -0,0 +1,415 @@
|
||||
# Carbon Performance Test Analysis Report
|
||||
|
||||
## Overview
|
||||
|
||||
This report provides a comprehensive performance analysis of the Carbon date and time library, covering performance aspects of core functional modules, calendar conversions, type operations, and other areas. The testing uses Go's standard benchmarking framework, including sequential execution, concurrent execution, and parallel execution modes.
|
||||
|
||||
## Test Environment
|
||||
|
||||
- **Operating System**: macOS 14.5.0
|
||||
- **Go Version**: 1.21+
|
||||
- **CPU**: Apple Silicon M1/M2
|
||||
- **Testing Framework**: Go testing package
|
||||
- **Test Modes**: sequential, concurrent, parallel
|
||||
|
||||
## Core Functional Module Performance Analysis
|
||||
|
||||
### Carbon Instance Creation Performance
|
||||
|
||||
#### NewCarbon Performance Test
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~55ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Carbon instance creation performance is excellent, with single operation taking approximately 50-60 nanoseconds
|
||||
- Zero memory allocation overhead, extremely high memory efficiency
|
||||
- Stable performance in concurrent and parallel modes with no significant performance degradation
|
||||
|
||||
#### Copy Operation Performance Test
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~120ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~140ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~130ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Copy operation performance is good, with single operation taking approximately 120-140 nanoseconds
|
||||
- Each operation allocates 48 bytes of memory, controllable memory overhead
|
||||
- Good concurrency safety with stable performance
|
||||
|
||||
#### Sleep Operation Performance Test
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**Performance Comparison for Different Time Intervals**:
|
||||
|
||||
| Time Interval | Avg Duration | Performance Rating |
|
||||
|---------------|--------------|-------------------|
|
||||
| 1ns | ~50ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1μs | ~60ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1ms | ~80ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1s | ~100ns | ⭐⭐⭐⭐ |
|
||||
| 1min | ~120ns | ⭐⭐⭐⭐ |
|
||||
| 1hour | ~150ns | ⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Sleep operation performance is excellent with zero memory allocation overhead
|
||||
- Larger time intervals slightly increase operation duration, but overall performance remains stable
|
||||
- Good concurrency safety
|
||||
|
||||
## Type System Performance Analysis
|
||||
|
||||
### Carbon Type Operation Performance
|
||||
|
||||
#### Scan Operation Performance
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~90ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~85ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### Value Operation Performance
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~70ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~75ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON Serialization Performance
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~850ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~820ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON Deserialization Performance
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~1200ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~1300ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~1250ns | 512 B/op | ⭐⭐⭐ |
|
||||
|
||||
#### String Conversion Performance
|
||||
|
||||
| Test Mode | Operations | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|------------|--------------|-------------------|-------------------|
|
||||
| Sequential | 10,000 | ~150ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~160ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~155ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Basic type operations (Scan, Value) have excellent performance with zero memory allocation
|
||||
- JSON serialization performance is good, deserialization is relatively slower but acceptable
|
||||
- String conversion performance is stable with low memory overhead
|
||||
|
||||
### Built-in Type Performance Comparison
|
||||
|
||||
#### Built-in Type vs Carbon Type Performance Comparison
|
||||
|
||||
| Operation Type | Built-in Duration | Carbon Duration | Performance Difference | Recommended Usage |
|
||||
|----------------|-------------------|-----------------|----------------------|-------------------|
|
||||
| Scan | ~60ns | ~80ns | +33% | Built-in type |
|
||||
| Value | ~50ns | ~70ns | +40% | Built-in type |
|
||||
| MarshalJSON | ~600ns | ~800ns | +33% | Built-in type |
|
||||
| UnmarshalJSON | ~1000ns | ~1200ns | +20% | Built-in type |
|
||||
| String | ~100ns | ~150ns | +50% | Built-in type |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Built-in types outperform Carbon types in terms of performance
|
||||
- For high-performance scenarios, built-in types are recommended
|
||||
- Carbon types provide more functionality, suitable for scenarios requiring extended features
|
||||
|
||||
## Calendar Conversion Performance Analysis
|
||||
|
||||
### Hebrew Calendar Performance Test
|
||||
|
||||
#### Gregorian to Hebrew Calendar Performance
|
||||
|
||||
| Test Date | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|--------------|-------------------|-------------------|
|
||||
| 2024-01-01 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-03-20 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-06-21 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-09-22 | ~230ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-12-21 | ~240ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### Hebrew to Gregorian Calendar Performance
|
||||
|
||||
| Test Date | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------|--------------|-------------------|-------------------|
|
||||
| 5784-01-01 | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-06-15 | ~190ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-12-29 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 5785-01-01 | ~185ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5785-12-30 | ~195ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### Hebrew Calendar Basic Operation Performance
|
||||
|
||||
| Operation Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|----------------|--------------|-------------------|-------------------|
|
||||
| Year() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Month() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Day() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| String() | ~50ns | 16 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| IsLeapYear() | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToMonthString() | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToWeekString() | ~120ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### Hebrew Calendar Algorithm Performance
|
||||
|
||||
| Algorithm Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|----------------|--------------|-------------------|-------------------|
|
||||
| gregorian2jdn | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| hebrew2jdn | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2hebrew | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2gregorian | ~160ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Hebrew calendar conversion performance is excellent, with single operation taking 180-240 nanoseconds
|
||||
- Basic operations (year, month, day) have exceptional performance, approaching zero overhead
|
||||
- Algorithm implementation is efficient with zero memory allocation overhead
|
||||
- String operation performance is good with controllable memory overhead
|
||||
|
||||
### Persian Calendar Performance Test
|
||||
|
||||
#### Persian Calendar Conversion Performance
|
||||
|
||||
| Operation Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|----------------|--------------|-------------------|-------------------|
|
||||
| FromStdTime | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Basic Operations | ~10ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Persian calendar conversion performance is good, with single operation taking 250-300 nanoseconds
|
||||
- Algorithm implementation is efficient with zero memory allocation overhead
|
||||
- Basic operations have excellent performance
|
||||
|
||||
### Julian Calendar Performance Test
|
||||
|
||||
#### Julian Calendar Conversion Performance
|
||||
|
||||
| Operation Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|----------------|--------------|-------------------|-------------------|
|
||||
| FromStdTime | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Basic Operations | ~8ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Julian calendar conversion performance is excellent, with single operation taking 200-250 nanoseconds
|
||||
- Algorithm implementation is efficient with zero memory allocation overhead
|
||||
- Basic operations have exceptional performance
|
||||
|
||||
### Lunar Calendar Performance Test
|
||||
|
||||
#### Lunar Calendar Conversion Performance
|
||||
|
||||
| Operation Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|----------------|--------------|-------------------|-------------------|
|
||||
| FromStdTime | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~350ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Basic Operations | ~12ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Lunar calendar conversion performance is good, with single operation taking 300-350 nanoseconds
|
||||
- Algorithm is relatively complex but performance is still acceptable
|
||||
- Basic operations have excellent performance
|
||||
|
||||
## Advanced Function Performance Analysis
|
||||
|
||||
### Outputter Performance Test
|
||||
|
||||
#### Formatting Output Performance
|
||||
|
||||
| Format Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-------------|--------------|-------------------|-------------------|
|
||||
| Standard Format | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Custom Format | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| Complex Format | ~500ns | 128 B/op | ⭐⭐⭐ |
|
||||
| JSON Format | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### Multi-language Output Performance
|
||||
|
||||
| Language Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|---------------|--------------|-------------------|-------------------|
|
||||
| Chinese | ~150ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| English | ~120ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Japanese | ~180ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| Korean | ~160ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Standard format output performance is excellent
|
||||
- Custom format performance is good
|
||||
- Multi-language support performance is stable
|
||||
- Complex formats are relatively slower but still within acceptable range
|
||||
|
||||
### Parser Performance Test
|
||||
|
||||
#### String Parsing Performance
|
||||
|
||||
| Parsing Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|--------------|--------------|-------------------|-------------------|
|
||||
| Standard Format | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| Custom Format | ~400ns | 128 B/op | ⭐⭐⭐ |
|
||||
| Complex Format | ~800ns | 256 B/op | ⭐⭐⭐ |
|
||||
| Error Format | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Standard format parsing performance is good
|
||||
- Custom format parsing is relatively slower
|
||||
- Error handling performance is excellent
|
||||
|
||||
### Comparer Performance Test
|
||||
|
||||
#### Date Comparison Performance
|
||||
|
||||
| Comparison Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|-----------------|--------------|-------------------|-------------------|
|
||||
| Equality Comparison | ~20ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Size Comparison | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Range Comparison | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Complex Comparison | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Comparison operations have exceptional performance, approaching zero overhead
|
||||
- Zero memory allocation, extremely high efficiency
|
||||
- Suitable for high-frequency comparison scenarios
|
||||
|
||||
### Traveler Function Performance Test
|
||||
|
||||
#### Time Travel Performance
|
||||
|
||||
| Operation Type | Avg Duration | Memory Allocation | Performance Rating |
|
||||
|----------------|--------------|-------------------|-------------------|
|
||||
| AddYear | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMonth | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddDay | ~40ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddHour | ~35ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMinute | ~30ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddSecond | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Time travel function performance is excellent
|
||||
- All operations have zero memory allocation overhead
|
||||
- Suitable for frequent time calculation scenarios
|
||||
|
||||
## Memory Usage Analysis
|
||||
|
||||
### Memory Allocation Statistics
|
||||
|
||||
| Module Type | Avg Memory Allocation | Max Memory Allocation | Memory Efficiency Rating |
|
||||
|-------------|----------------------|----------------------|--------------------------|
|
||||
| Core Operations | 0-48 B/op | 64 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Type Conversion | 0-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| Calendar Conversion | 0 B/op | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Formatting Output | 32-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| String Parsing | 64-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Calendar conversion modules have the highest memory efficiency with zero allocation
|
||||
- Core operations have excellent memory efficiency
|
||||
- String operations have controllable memory overhead
|
||||
- Overall memory usage efficiency is good
|
||||
|
||||
## Concurrency Performance Analysis
|
||||
|
||||
### Concurrency Safety Test
|
||||
|
||||
| Test Scenario | Performance Degradation | Memory Leak | Concurrency Safety Rating |
|
||||
|---------------|------------------------|-------------|---------------------------|
|
||||
| High Concurrency Creation | <5% | None | ⭐⭐⭐⭐⭐ |
|
||||
| High Concurrency Conversion | <10% | None | ⭐⭐⭐⭐⭐ |
|
||||
| High Concurrency Comparison | <3% | None | ⭐⭐⭐⭐⭐ |
|
||||
| High Concurrency Formatting | <15% | None | ⭐⭐⭐⭐ |
|
||||
|
||||
**Analysis Conclusion**:
|
||||
- Carbon library has good concurrency safety
|
||||
- Performance degradation is minimal in high concurrency scenarios
|
||||
- No memory leak issues
|
||||
- Suitable for high concurrency application scenarios
|
||||
|
||||
## Performance Optimization Recommendations
|
||||
|
||||
### Performance Optimization Strategies
|
||||
|
||||
#### Code-level Optimization
|
||||
|
||||
**Object Reuse**:
|
||||
- For frequently used Carbon instances, reuse instead of recreating
|
||||
- Use object pool pattern to reduce memory allocation
|
||||
|
||||
**Caching Strategy**:
|
||||
- Add result caching for complex calendar calculations
|
||||
- String formatting results can be cached
|
||||
|
||||
**Algorithm Optimization**:
|
||||
- Lunar calendar algorithm is relatively complex, can be further optimized
|
||||
- JSON serialization can use more efficient implementations
|
||||
|
||||
#### Usage Recommendations
|
||||
|
||||
**High-performance Scenarios**:
|
||||
- Use built-in types instead of Carbon types
|
||||
- Avoid frequent string formatting
|
||||
- Reuse Carbon instances
|
||||
|
||||
**General Scenarios**:
|
||||
- Carbon types provide better functional support
|
||||
- Formatting output performance is sufficient for requirements
|
||||
|
||||
**Calendar Conversion Scenarios**:
|
||||
- Hebrew and Julian calendars have the best performance
|
||||
- Lunar calendar conversion is relatively slower but still acceptable
|
||||
|
||||
## Summary
|
||||
|
||||
### Overall Performance Assessment
|
||||
|
||||
| Performance Dimension | Rating | Evaluation |
|
||||
|----------------------|--------|------------|
|
||||
| Execution Efficiency | ⭐⭐⭐⭐⭐ | Excellent core operation performance |
|
||||
| Memory Efficiency | ⭐⭐⭐⭐⭐ | High memory usage efficiency |
|
||||
| Concurrency Performance | ⭐⭐⭐⭐⭐ | Good concurrency safety |
|
||||
| Function Completeness | ⭐⭐⭐⭐⭐ | Rich and complete functionality |
|
||||
| Usability | ⭐⭐⭐⭐⭐ | User-friendly API design |
|
||||
|
||||
### Performance Highlights
|
||||
|
||||
**Exceptional Basic Performance**: Core operations take 50-200 nanoseconds
|
||||
|
||||
**Zero Memory Allocation**: Calendar conversion and basic operations have zero memory allocation overhead
|
||||
|
||||
**Excellent Concurrency Performance**: Performance degradation is less than 15% in high concurrency scenarios
|
||||
|
||||
**Rich Function Support**: Supports multiple calendars and formatting options
|
||||
|
||||
**Good Extensibility**: Supports custom formats and types
|
||||
|
||||
### Improvement Directions
|
||||
|
||||
**Lunar Algorithm Optimization**: Lunar calendar conversion algorithm can be further optimized
|
||||
|
||||
**JSON Performance Enhancement**: Consider using more efficient JSON serialization libraries
|
||||
|
||||
**Caching Mechanism**: Add result caching for complex calculations
|
||||
|
||||
**Memory Pool**: Implement object pools for high-frequency operations
|
||||
|
||||
The Carbon project demonstrates excellent overall performance, particularly outstanding in core functionality and calendar conversion aspects. It is a high-performance, feature-complete date and time processing library.
|
||||
|
||||
414
vendor/github.com/dromara/carbon/v2/test_report.ja.md
generated
vendored
Normal file
414
vendor/github.com/dromara/carbon/v2/test_report.ja.md
generated
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
# Carbon パフォーマンステスト分析レポート
|
||||
|
||||
## 概要
|
||||
|
||||
本レポートは、Carbon 日時ライブラリの包括的なパフォーマンステスト分析を行い、コア機能モジュール、暦法変換、型操作など各方面のパフォーマンスを検証しました。テストは Go 標準ベンチマークフレームワークを使用し、順次実行、並行実行、並列実行の3つのモードを含みます。
|
||||
|
||||
## テスト環境
|
||||
|
||||
- **オペレーティングシステム**: macOS 14.5.0
|
||||
- **Go バージョン**: 1.21+
|
||||
- **CPU**: Apple Silicon M1/M2
|
||||
- **テストフレームワーク**: Go testing package
|
||||
- **テストモード**: sequential(順次)、concurrent(並行)、parallel(並列)
|
||||
|
||||
## コア機能モジュールパフォーマンス分析
|
||||
|
||||
### Carbon インスタンス作成パフォーマンス
|
||||
|
||||
#### NewCarbon パフォーマンステスト
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~55ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- Carbon インスタンス作成パフォーマンスは優秀で、単一操作の所要時間は約50-60ナノ秒
|
||||
- メモリ割り当てオーバーヘッドなし、メモリ効率が極めて高い
|
||||
- 並行・並列モードでのパフォーマンスが安定し、顕著な性能劣化なし
|
||||
|
||||
#### Copy 操作パフォーマンステスト
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~120ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~140ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~130ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- Copy 操作パフォーマンスは良好で、単一操作の所要時間は約120-140ナノ秒
|
||||
- 各操作で48バイトのメモリを割り当て、メモリオーバーヘッドは制御可能
|
||||
- 並行安全性が良好で、パフォーマンスが安定
|
||||
|
||||
#### Sleep 操作パフォーマンステスト
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**異なる時間間隔でのパフォーマンス比較**:
|
||||
|
||||
| 時間間隔 | 平均所要時間 | パフォーマンス評価 |
|
||||
|----------|-------------|------------------|
|
||||
| 1ns | ~50ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1μs | ~60ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1ms | ~80ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1s | ~100ns | ⭐⭐⭐⭐ |
|
||||
| 1min | ~120ns | ⭐⭐⭐⭐ |
|
||||
| 1hour | ~150ns | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- Sleep 操作パフォーマンスは優秀で、メモリ割り当てオーバーヘッドなし
|
||||
- 時間間隔が大きくなるにつれて操作時間が若干増加するが、全体的なパフォーマンスは安定
|
||||
- 並行安全性が良好
|
||||
|
||||
## 型システムパフォーマンス分析
|
||||
|
||||
### Carbon 型操作パフォーマンス
|
||||
|
||||
#### Scan 操作パフォーマンス
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~90ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~85ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### Value 操作パフォーマンス
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~70ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~75ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON シリアライゼーションパフォーマンス
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~850ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~820ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON デシリアライゼーションパフォーマンス
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~1200ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~1300ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~1250ns | 512 B/op | ⭐⭐⭐ |
|
||||
|
||||
#### String 変換パフォーマンス
|
||||
|
||||
| テストモード | 操作回数 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-------------|----------|-------------|---------------|------------------|
|
||||
| Sequential | 10,000 | ~150ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~160ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~155ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 基本型操作(Scan、Value)のパフォーマンスは優秀で、メモリ割り当てなし
|
||||
- JSON シリアライゼーションパフォーマンスは良好、デシリアライゼーションは比較的遅いが許容範囲
|
||||
- String 変換パフォーマンスは安定し、メモリオーバーヘッドが小さい
|
||||
|
||||
### 組み込み型パフォーマンス比較
|
||||
|
||||
#### 組み込み型 vs Carbon 型パフォーマンス比較
|
||||
|
||||
| 操作タイプ | 組み込み型所要時間 | Carbon型所要時間 | パフォーマンス差 | 推奨使用 |
|
||||
|-----------|------------------|-----------------|----------------|----------|
|
||||
| Scan | ~60ns | ~80ns | +33% | 組み込み型 |
|
||||
| Value | ~50ns | ~70ns | +40% | 組み込み型 |
|
||||
| MarshalJSON | ~600ns | ~800ns | +33% | 組み込み型 |
|
||||
| UnmarshalJSON | ~1000ns | ~1200ns | +20% | 組み込み型 |
|
||||
| String | ~100ns | ~150ns | +50% | 組み込み型 |
|
||||
|
||||
**分析結論**:
|
||||
- 組み込み型は Carbon 型よりパフォーマンスが優れている
|
||||
- 高パフォーマンスシナリオでは組み込み型を推奨
|
||||
- Carbon 型はより多くの機能を提供し、拡張機能が必要なシナリオに適している
|
||||
|
||||
## 暦法変換パフォーマンス分析
|
||||
|
||||
### ヘブライ暦パフォーマンステスト
|
||||
|
||||
#### グレゴリオ暦からヘブライ暦への変換パフォーマンス
|
||||
|
||||
| テスト日付 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| 2024-01-01 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-03-20 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-06-21 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-09-22 | ~230ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-12-21 | ~240ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### ヘブライ暦からグレゴリオ暦への変換パフォーマンス
|
||||
|
||||
| テスト日付 | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| 5784-01-01 | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-06-15 | ~190ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-12-29 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 5785-01-01 | ~185ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5785-12-30 | ~195ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### ヘブライ暦基本操作パフォーマンス
|
||||
|
||||
| 操作タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| Year() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Month() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Day() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| String() | ~50ns | 16 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| IsLeapYear() | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToMonthString() | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToWeekString() | ~120ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### ヘブライ暦アルゴリズムパフォーマンス
|
||||
|
||||
| アルゴリズムタイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|------------------|-------------|---------------|------------------|
|
||||
| gregorian2jdn | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| hebrew2jdn | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2hebrew | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2gregorian | ~160ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- ヘブライ暦変換パフォーマンスは優秀で、単一操作の所要時間は180-240ナノ秒
|
||||
- 基本操作(年、月、日)のパフォーマンスは極めて優秀で、オーバーヘッドに近い
|
||||
- アルゴリズム実装が効率的で、メモリ割り当てオーバーヘッドなし
|
||||
- 文字列操作パフォーマンスは良好で、メモリオーバーヘッドは制御可能
|
||||
|
||||
### ペルシア暦パフォーマンステスト
|
||||
|
||||
#### ペルシア暦変換パフォーマンス
|
||||
|
||||
| 操作タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| FromStdTime | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 基本操作 | ~10ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- ペルシア暦変換パフォーマンスは良好で、単一操作の所要時間は250-300ナノ秒
|
||||
- アルゴリズム実装が効率的で、メモリ割り当てオーバーヘッドなし
|
||||
- 基本操作パフォーマンスは優秀
|
||||
|
||||
### ユリウス暦パフォーマンステスト
|
||||
|
||||
#### ユリウス暦変換パフォーマンス
|
||||
|
||||
| 操作タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| FromStdTime | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 基本操作 | ~8ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- ユリウス暦変換パフォーマンスは優秀で、単一操作の所要時間は200-250ナノ秒
|
||||
- アルゴリズム実装が効率的で、メモリ割り当てオーバーヘッドなし
|
||||
- 基本操作パフォーマンスは極めて優秀
|
||||
|
||||
### 太陰暦パフォーマンステスト
|
||||
|
||||
#### 太陰暦変換パフォーマンス
|
||||
|
||||
| 操作タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| FromStdTime | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~350ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 基本操作 | ~12ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 太陰暦変換パフォーマンスは良好で、単一操作の所要時間は300-350ナノ秒
|
||||
- アルゴリズムは比較的複雑だが、パフォーマンスは許容範囲内
|
||||
- 基本操作パフォーマンスは優秀
|
||||
|
||||
## 高度機能パフォーマンス分析
|
||||
|
||||
### 出力器パフォーマンステスト
|
||||
|
||||
#### フォーマット出力パフォーマンス
|
||||
|
||||
| フォーマットタイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|------------------|-------------|---------------|------------------|
|
||||
| 標準フォーマット | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| カスタムフォーマット | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 複雑フォーマット | ~500ns | 128 B/op | ⭐⭐⭐ |
|
||||
| JSONフォーマット | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### 多言語出力パフォーマンス
|
||||
|
||||
| 言語タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| 中国語 | ~150ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| 英語 | ~120ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 日本語 | ~180ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 韓国語 | ~160ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 標準フォーマット出力パフォーマンスは優秀
|
||||
- カスタムフォーマットパフォーマンスは良好
|
||||
- 多言語サポートパフォーマンスは安定
|
||||
- 複雑フォーマットは比較的遅いが、許容範囲内
|
||||
|
||||
### パーサーパフォーマンステスト
|
||||
|
||||
#### 文字列解析パフォーマンス
|
||||
|
||||
| 解析タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| 標準フォーマット | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| カスタムフォーマット | ~400ns | 128 B/op | ⭐⭐⭐ |
|
||||
| 複雑フォーマット | ~800ns | 256 B/op | ⭐⭐⭐ |
|
||||
| エラーフォーマット | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 標準フォーマット解析パフォーマンスは良好
|
||||
- カスタムフォーマット解析は比較的遅い
|
||||
- エラー処理パフォーマンスは優秀
|
||||
|
||||
### 比較器パフォーマンステスト
|
||||
|
||||
#### 日付比較パフォーマンス
|
||||
|
||||
| 比較タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| 等価比較 | ~20ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 大小比較 | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 範囲比較 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 複雑比較 | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 比較操作パフォーマンスは極めて優秀で、オーバーヘッドに近い
|
||||
- メモリ割り当てなし、効率が極めて高い
|
||||
- 高頻度比較シナリオに適している
|
||||
|
||||
### トラベラー機能パフォーマンステスト
|
||||
|
||||
#### 時間旅行パフォーマンス
|
||||
|
||||
| 操作タイプ | 平均所要時間 | メモリ割り当て | パフォーマンス評価 |
|
||||
|-----------|-------------|---------------|------------------|
|
||||
| AddYear | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMonth | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddDay | ~40ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddHour | ~35ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMinute | ~30ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddSecond | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 時間旅行機能パフォーマンスは優秀
|
||||
- すべての操作でメモリ割り当てオーバーヘッドなし
|
||||
- 頻繁な時間計算シナリオに適している
|
||||
|
||||
## メモリ使用分析
|
||||
|
||||
### メモリ割り当て統計
|
||||
|
||||
| モジュールタイプ | 平均メモリ割り当て | 最大メモリ割り当て | メモリ効率評価 |
|
||||
|-----------------|-------------------|-------------------|---------------|
|
||||
| コア操作 | 0-48 B/op | 64 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 型変換 | 0-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| 暦法変換 | 0 B/op | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| フォーマット出力 | 32-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| 文字列解析 | 64-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- 暦法変換モジュールのメモリ効率が最高で、割り当てなし
|
||||
- コア操作のメモリ効率は優秀
|
||||
- 文字列操作のメモリオーバーヘッドは制御可能
|
||||
- 全体的なメモリ使用効率は良好
|
||||
|
||||
## 並行パフォーマンス分析
|
||||
|
||||
### 並行安全性テスト
|
||||
|
||||
| テストシナリオ | パフォーマンス劣化 | メモリリーク | 並行安全性評価 |
|
||||
|---------------|-------------------|-------------|---------------|
|
||||
| 高並行作成 | <5% | なし | ⭐⭐⭐⭐⭐ |
|
||||
| 高並行変換 | <10% | なし | ⭐⭐⭐⭐⭐ |
|
||||
| 高並行比較 | <3% | なし | ⭐⭐⭐⭐⭐ |
|
||||
| 高並行フォーマット | <15% | なし | ⭐⭐⭐⭐ |
|
||||
|
||||
**分析結論**:
|
||||
- Carbon ライブラリは良好な並行安全性を持つ
|
||||
- 高並行シナリオでのパフォーマンス劣化は最小
|
||||
- メモリリーク問題なし
|
||||
- 高並行アプリケーションシナリオに適している
|
||||
|
||||
## パフォーマンス最適化提案
|
||||
|
||||
### パフォーマンス最適化戦略
|
||||
|
||||
#### コードレベル最適化
|
||||
|
||||
**オブジェクト再利用**:
|
||||
- 頻繁に使用される Carbon インスタンスは、再作成ではなく再利用を推奨
|
||||
- オブジェクトプールパターンを使用してメモリ割り当てを削減
|
||||
|
||||
**キャッシュ戦略**:
|
||||
- 複雑な暦法計算には結果キャッシュを追加
|
||||
- 文字列フォーマット結果はキャッシュ可能
|
||||
|
||||
**アルゴリズム最適化**:
|
||||
- 太陰暦アルゴリズムは比較的複雑なので、さらなる最適化が可能
|
||||
- JSON シリアライゼーションにはより効率的な実装を使用可能
|
||||
|
||||
#### 使用推奨事項
|
||||
|
||||
**高パフォーマンスシナリオ**:
|
||||
- Carbon 型ではなく組み込み型を使用
|
||||
- 頻繁な文字列フォーマットを避ける
|
||||
- Carbon インスタンスを再利用
|
||||
|
||||
**一般的なシナリオ**:
|
||||
- Carbon 型はより良い機能サポートを提供
|
||||
- フォーマット出力パフォーマンスは要件を満たすのに十分
|
||||
|
||||
**暦法変換シナリオ**:
|
||||
- ヘブライ暦とユリウス暦のパフォーマンスが最高
|
||||
- 太陰暦変換は比較的遅いが、許容範囲内
|
||||
|
||||
## 総括
|
||||
|
||||
### パフォーマンス評価
|
||||
|
||||
| パフォーマンス次元 | 評価 | 評定 |
|
||||
|-------------------|------|------|
|
||||
| 実行効率 | ⭐⭐⭐⭐⭐ | コア操作パフォーマンス優秀 |
|
||||
| メモリ効率 | ⭐⭐⭐⭐⭐ | メモリ使用効率が高い |
|
||||
| 並行パフォーマンス | ⭐⭐⭐⭐⭐ | 並行安全性が良好 |
|
||||
| 機能完全性 | ⭐⭐⭐⭐⭐ | 機能が豊富で完全 |
|
||||
| 使いやすさ | ⭐⭐⭐⭐⭐ | API 設計が親しみやすい |
|
||||
|
||||
### パフォーマンスハイライト
|
||||
|
||||
**極めて優秀な基本パフォーマンス**:コア操作の所要時間は50-200ナノ秒範囲
|
||||
|
||||
**ゼロメモリ割り当て**:暦法変換と基本操作でメモリ割り当てオーバーヘッドなし
|
||||
|
||||
**優秀な並行パフォーマンス**:高並行シナリオでのパフォーマンス劣化は15%未満
|
||||
|
||||
**豊富な機能サポート**:複数の暦法とフォーマットオプションをサポート
|
||||
|
||||
**良好な拡張性**:カスタムフォーマットと型をサポート
|
||||
|
||||
### 改善方向
|
||||
|
||||
**太陰暦アルゴリズム最適化**:太陰暦変換アルゴリズムのさらなる最適化が可能
|
||||
|
||||
**JSON パフォーマンス向上**:より効率的な JSON シリアライゼーションライブラリの検討
|
||||
|
||||
**キャッシュメカニズム**:複雑な計算に結果キャッシュを追加
|
||||
|
||||
**メモリプール**:高頻度操作にオブジェクトプールを実装
|
||||
|
||||
Carbon プロジェクトは全体的なパフォーマンスが優秀で、特にコア機能と暦法変換の面で際立った性能を示しており、高パフォーマンスで機能完全な日時処理ライブラリです。
|
||||
414
vendor/github.com/dromara/carbon/v2/test_report.ko.md
generated
vendored
Normal file
414
vendor/github.com/dromara/carbon/v2/test_report.ko.md
generated
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
# Carbon 성능 테스트 분석 보고서
|
||||
|
||||
## 개요
|
||||
|
||||
본 보고서는 Carbon 날짜 시간 라이브러리에 대한 포괄적인 성능 테스트 분석을 수행하여, 핵심 기능 모듈, 역법 변환, 타입 작업 등 각 방면의 성능을 검증했습니다. 테스트는 Go 표준 벤치마크 프레임워크를 사용하며, 순차 실행, 동시 실행, 병렬 실행의 3가지 모드를 포함합니다.
|
||||
|
||||
## 테스트 환경
|
||||
|
||||
- **운영체제**: macOS 14.5.0
|
||||
- **Go 버전**: 1.21+
|
||||
- **CPU**: Apple Silicon M1/M2
|
||||
- **테스트 프레임워크**: Go testing package
|
||||
- **테스트 모드**: sequential(순차)、concurrent(동시)、parallel(병렬)
|
||||
|
||||
## 핵심 기능 모듈 성능 분석
|
||||
|
||||
### Carbon 인스턴스 생성 성능
|
||||
|
||||
#### NewCarbon 성능 테스트
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~55ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- Carbon 인스턴스 생성 성능이 우수하며, 단일 작업 소요 시간은 약 50-60 나노초
|
||||
- 메모리 할당 오버헤드 없음, 메모리 효율성이 극도로 높음
|
||||
- 동시 및 병렬 모드에서 성능이 안정적이며, 뚜렷한 성능 저하 없음
|
||||
|
||||
#### Copy 작업 성능 테스트
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~120ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~140ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~130ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- Copy 작업 성능이 양호하며, 단일 작업 소요 시간은 약 120-140 나노초
|
||||
- 각 작업마다 48바이트 메모리 할당, 메모리 오버헤드 제어 가능
|
||||
- 동시성 안전성이 양호하며, 성능이 안정적
|
||||
|
||||
#### Sleep 작업 성능 테스트
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**다른 시간 간격별 성능 비교**:
|
||||
|
||||
| 시간 간격 | 평균 소요 시간 | 성능 등급 |
|
||||
|----------|---------------|-----------|
|
||||
| 1ns | ~50ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1μs | ~60ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1ms | ~80ns | ⭐⭐⭐⭐⭐ |
|
||||
| 1s | ~100ns | ⭐⭐⭐⭐ |
|
||||
| 1min | ~120ns | ⭐⭐⭐⭐ |
|
||||
| 1hour | ~150ns | ⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- Sleep 작업 성능이 우수하며, 메모리 할당 오버헤드 없음
|
||||
- 시간 간격이 클수록 작업 시간이 약간 증가하지만, 전체적인 성능은 안정적
|
||||
- 동시성 안전성이 양호
|
||||
|
||||
## 타입 시스템 성능 분석
|
||||
|
||||
### Carbon 타입 작업 성능
|
||||
|
||||
#### Scan 작업 성능
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~90ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~85ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### Value 작업 성능
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~70ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~75ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON 직렬화 성능
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~850ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~820ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### JSON 역직렬화 성능
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~1200ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~1300ns | 512 B/op | ⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~1250ns | 512 B/op | ⭐⭐⭐ |
|
||||
|
||||
#### String 변환 성능
|
||||
|
||||
| 테스트 모드 | 작업 횟수 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|----------|---------------|-------------|-----------|
|
||||
| Sequential | 10,000 | ~150ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Concurrent | 10,000 | ~160ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
| Parallel | 10,000 | ~155ns | 32 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 기본 타입 작업(Scan、Value)성능이 우수하며, 메모리 할당 없음
|
||||
- JSON 직렬화 성능이 양호하며, 역직렬화는 상대적으로 느리지만 수용 가능
|
||||
- String 변환 성능이 안정적이며, 메모리 오버헤드가 작음
|
||||
|
||||
### 내장 타입 성능 비교
|
||||
|
||||
#### 내장 타입 vs Carbon 타입 성능 비교
|
||||
|
||||
| 작업 타입 | 내장 타입 소요 시간 | Carbon 타입 소요 시간 | 성능 차이 | 권장 사용 |
|
||||
|----------|-------------------|---------------------|----------|----------|
|
||||
| Scan | ~60ns | ~80ns | +33% | 내장 타입 |
|
||||
| Value | ~50ns | ~70ns | +40% | 내장 타입 |
|
||||
| MarshalJSON | ~600ns | ~800ns | +33% | 내장 타입 |
|
||||
| UnmarshalJSON | ~1000ns | ~1200ns | +20% | 내장 타입 |
|
||||
| String | ~100ns | ~150ns | +50% | 내장 타입 |
|
||||
|
||||
**분석 결론**:
|
||||
- 내장 타입이 Carbon 타입보다 성능이 우수함
|
||||
- 고성능 시나리오에서는 내장 타입 권장
|
||||
- Carbon 타입은 더 많은 기능을 제공하며, 확장 기능이 필요한 시나리오에 적합
|
||||
|
||||
## 역법 변환 성능 분석
|
||||
|
||||
### 히브리력 성능 테스트
|
||||
|
||||
#### 그레고리력에서 히브리력으로의 변환 성능
|
||||
|
||||
| 테스트 날짜 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|---------------|-------------|-----------|
|
||||
| 2024-01-01 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-03-20 | ~220ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-06-21 | ~210ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-09-22 | ~230ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 2024-12-21 | ~240ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### 히브리력에서 그레고리력으로의 변환 성능
|
||||
|
||||
| 테스트 날짜 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|------------|---------------|-------------|-----------|
|
||||
| 5784-01-01 | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-06-15 | ~190ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5784-12-29 | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 5785-01-01 | ~185ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 5785-12-30 | ~195ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### 히브리력 기본 작업 성능
|
||||
|
||||
| 작업 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| Year() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Month() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| Day() | ~5ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| String() | ~50ns | 16 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| IsLeapYear() | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToMonthString() | ~80ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToWeekString() | ~120ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
#### 히브리력 알고리즘 성능
|
||||
|
||||
| 알고리즘 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|-------------|---------------|-------------|-----------|
|
||||
| gregorian2jdn | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| hebrew2jdn | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2hebrew | ~180ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| jdn2gregorian | ~160ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 히브리력 변환 성능이 우수하며, 단일 작업 소요 시간은 180-240 나노초
|
||||
- 기본 작업(년、월、일)성능이 극도로 우수하며, 오버헤드에 근접
|
||||
- 알고리즘 구현이 효율적이며, 메모리 할당 오버헤드 없음
|
||||
- 문자열 작업 성능이 양호하며, 메모리 오버헤드 제어 가능
|
||||
|
||||
### 페르시아력 성능 테스트
|
||||
|
||||
#### 페르시아력 변환 성능
|
||||
|
||||
| 작업 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| FromStdTime | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~150ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 기본 작업 | ~10ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 페르시아력 변환 성능이 양호하며, 단일 작업 소요 시간은 250-300 나노초
|
||||
- 알고리즘 구현이 효율적이며, 메모리 할당 오버헤드 없음
|
||||
- 기본 작업 성능이 우수
|
||||
|
||||
### 율리우스력 성능 테스트
|
||||
|
||||
#### 율리우스력 변환 성능
|
||||
|
||||
| 작업 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| FromStdTime | ~200ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~250ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 기본 작업 | ~8ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 율리우스력 변환 성능이 우수하며, 단일 작업 소요 시간은 200-250 나노초
|
||||
- 알고리즘 구현이 효율적이며, 메모리 할당 오버헤드 없음
|
||||
- 기본 작업 성능이 극도로 우수
|
||||
|
||||
### 음력 성능 테스트
|
||||
|
||||
#### 음력 변환 성능
|
||||
|
||||
| 작업 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| FromStdTime | ~300ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| ToGregorian | ~350ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| IsLeapYear | ~200ns | 0 B/op | ⭐⭐⭐⭐ |
|
||||
| 기본 작업 | ~12ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 음력 변환 성능이 양호하며, 단일 작업 소요 시간은 300-350 나노초
|
||||
- 알고리즘이 상대적으로 복잡하지만, 성능은 수용 가능한 범위
|
||||
- 기본 작업 성능이 우수
|
||||
|
||||
## 고급 기능 성능 분석
|
||||
|
||||
### 출력기 성능 테스트
|
||||
|
||||
#### 포맷 출력 성능
|
||||
|
||||
| 포맷 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| 표준 포맷 | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 사용자 정의 포맷 | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 복잡한 포맷 | ~500ns | 128 B/op | ⭐⭐⭐ |
|
||||
| JSON 포맷 | ~800ns | 256 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
#### 다국어 출력 성능
|
||||
|
||||
| 언어 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| 중국어 | ~150ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
| 영어 | ~120ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 일본어 | ~180ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 한국어 | ~160ns | 48 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 표준 포맷 출력 성능이 우수
|
||||
- 사용자 정의 포맷 성능이 양호
|
||||
- 다국어 지원 성능이 안정적
|
||||
- 복잡한 포맷은 상대적으로 느리지만, 수용 가능한 범위 내
|
||||
|
||||
### 파서 성능 테스트
|
||||
|
||||
#### 문자열 파싱 성능
|
||||
|
||||
| 파싱 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| 표준 포맷 | ~200ns | 64 B/op | ⭐⭐⭐⭐ |
|
||||
| 사용자 정의 포맷 | ~400ns | 128 B/op | ⭐⭐⭐ |
|
||||
| 복잡한 포맷 | ~800ns | 256 B/op | ⭐⭐⭐ |
|
||||
| 오류 포맷 | ~100ns | 32 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 표준 포맷 파싱 성능이 양호
|
||||
- 사용자 정의 포맷 파싱이 상대적으로 느림
|
||||
- 오류 처리 성능이 우수
|
||||
|
||||
### 비교기 성능 테스트
|
||||
|
||||
#### 날짜 비교 성능
|
||||
|
||||
| 비교 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| 동등 비교 | ~20ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 크기 비교 | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 범위 비교 | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 복잡한 비교 | ~100ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 비교 작업 성능이 극도로 우수하며, 오버헤드에 근접
|
||||
- 메모리 할당 없음, 효율성이 극도로 높음
|
||||
- 고빈도 비교 시나리오에 적합
|
||||
|
||||
### 여행자 기능 성능 테스트
|
||||
|
||||
#### 시간 여행 성능
|
||||
|
||||
| 작업 타입 | 평균 소요 시간 | 메모리 할당 | 성능 등급 |
|
||||
|----------|---------------|-------------|-----------|
|
||||
| AddYear | ~50ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMonth | ~60ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddDay | ~40ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddHour | ~35ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddMinute | ~30ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| AddSecond | ~25ns | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 시간 여행 기능 성능이 우수
|
||||
- 모든 작업에서 메모리 할당 오버헤드 없음
|
||||
- 빈번한 시간 계산 시나리오에 적합
|
||||
|
||||
## 메모리 사용 분석
|
||||
|
||||
### 메모리 할당 통계
|
||||
|
||||
| 모듈 타입 | 평균 메모리 할당 | 최대 메모리 할당 | 메모리 효율성 등급 |
|
||||
|----------|-----------------|-----------------|-------------------|
|
||||
| 핵심 작업 | 0-48 B/op | 64 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 타입 변환 | 0-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| 역법 변환 | 0 B/op | 0 B/op | ⭐⭐⭐⭐⭐ |
|
||||
| 포맷 출력 | 32-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
| 문자열 파싱 | 64-256 B/op | 512 B/op | ⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- 역법 변환 모듈의 메모리 효율성이 최고이며, 할당 없음
|
||||
- 핵심 작업의 메모리 효율성이 우수
|
||||
- 문자열 작업의 메모리 오버헤드가 제어 가능
|
||||
- 전체적인 메모리 사용 효율성이 양호
|
||||
|
||||
## 동시성 성능 분석
|
||||
|
||||
### 동시성 안전성 테스트
|
||||
|
||||
| 테스트 시나리오 | 성능 저하 | 메모리 누수 | 동시성 안전성 등급 |
|
||||
|----------------|----------|------------|-------------------|
|
||||
| 고동시성 생성 | <5% | 없음 | ⭐⭐⭐⭐⭐ |
|
||||
| 고동시성 변환 | <10% | 없음 | ⭐⭐⭐⭐⭐ |
|
||||
| 고동시성 비교 | <3% | 없음 | ⭐⭐⭐⭐⭐ |
|
||||
| 고동시성 포맷 | <15% | 없음 | ⭐⭐⭐⭐ |
|
||||
|
||||
**분석 결론**:
|
||||
- Carbon 라이브러리는 양호한 동시성 안전성을 가짐
|
||||
- 고동시성 시나리오에서 성능 저하가 최소
|
||||
- 메모리 누수 문제 없음
|
||||
- 고동시성 애플리케이션 시나리오에 적합
|
||||
|
||||
## 성능 최적화 제안
|
||||
|
||||
### 성능 최적화 전략
|
||||
|
||||
#### 코드 레벨 최적화
|
||||
|
||||
**객체 재사용**:
|
||||
- 빈번히 사용되는 Carbon 인스턴스는 재생성보다 재사용 권장
|
||||
- 객체 풀 패턴을 사용하여 메모리 할당 감소
|
||||
|
||||
**캐싱 전략**:
|
||||
- 복잡한 역법 계산에는 결과 캐싱 추가
|
||||
- 문자열 포맷 결과는 캐싱 가능
|
||||
|
||||
**알고리즘 최적화**:
|
||||
- 음력 알고리즘이 상대적으로 복잡하므로, 추가 최적화 가능
|
||||
- JSON 직렬화에는 더 효율적인 구현 사용 가능
|
||||
|
||||
#### 사용 권장사항
|
||||
|
||||
**고성능 시나리오**:
|
||||
- Carbon 타입보다 내장 타입 사용
|
||||
- 빈번한 문자열 포맷팅 회피
|
||||
- Carbon 인스턴스 재사용
|
||||
|
||||
**일반 시나리오**:
|
||||
- Carbon 타입은 더 나은 기능 지원 제공
|
||||
- 포맷 출력 성능이 요구사항을 충족하기에 충분
|
||||
|
||||
**역법 변환 시나리오**:
|
||||
- 히브리력과 율리우스력의 성능이 최고
|
||||
- 음력 변환은 상대적으로 느리지만, 수용 가능한 범위
|
||||
|
||||
## 종합
|
||||
|
||||
### 성능 평가
|
||||
|
||||
| 성능 차원 | 평가 | 평정 |
|
||||
|----------|------|------|
|
||||
| 실행 효율성 | ⭐⭐⭐⭐⭐ | 핵심 작업 성능 우수 |
|
||||
| 메모리 효율성 | ⭐⭐⭐⭐⭐ | 메모리 사용 효율성이 높음 |
|
||||
| 동시성 성능 | ⭐⭐⭐⭐⭐ | 동시성 안전성이 양호 |
|
||||
| 기능 완전성 | ⭐⭐⭐⭐⭐ | 기능이 풍부하고 완전 |
|
||||
| 사용 편의성 | ⭐⭐⭐⭐⭐ | API 설계가 친근함 |
|
||||
|
||||
### 성능 하이라이트
|
||||
|
||||
**극도로 우수한 기본 성능**:핵심 작업 소요 시간은 50-200 나노초 범위
|
||||
|
||||
**제로 메모리 할당**:역법 변환과 기본 작업에서 메모리 할당 오버헤드 없음
|
||||
|
||||
**우수한 동시성 성능**:고동시성 시나리오에서 성능 저하는 15% 미만
|
||||
|
||||
**풍부한 기능 지원**:다양한 역법과 포맷 옵션 지원
|
||||
|
||||
**양호한 확장성**:사용자 정의 포맷과 타입 지원
|
||||
|
||||
### 개선 방향
|
||||
|
||||
**음력 알고리즘 최적화**:음력 변환 알고리즘의 추가 최적화 가능
|
||||
|
||||
**JSON 성능 향상**:더 효율적인 JSON 직렬화 라이브러리 검토
|
||||
|
||||
**캐싱 메커니즘**:복잡한 계산에 결과 캐싱 추가
|
||||
|
||||
**메모리 풀**:고빈도 작업에 객체 풀 구현
|
||||
|
||||
Carbon 프로젝트는 전체적인 성능이 우수하며, 특히 핵심 기능과 역법 변환 면에서 뛰어난 성능을 보여주며, 고성능이고 기능이 완전한 날짜 시간 처리 라이브러리입니다.
|
||||
2
vendor/github.com/dromara/carbon/v2/traveler.go
generated
vendored
2
vendor/github.com/dromara/carbon/v2/traveler.go
generated
vendored
@@ -20,6 +20,8 @@ func Now(timezone ...string) *Carbon {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
if IsTestNow() {
|
||||
frozenNow.rw.RLock()
|
||||
defer frozenNow.rw.RUnlock()
|
||||
return frozenNow.testNow.Copy().SetLocation(loc)
|
||||
}
|
||||
return CreateFromStdTime(time.Now().In(loc))
|
||||
|
||||
45
vendor/github.com/dromara/carbon/v2/type_builtin.go
generated
vendored
45
vendor/github.com/dromara/carbon/v2/type_builtin.go
generated
vendored
@@ -103,104 +103,59 @@ func (t timestampType) Precision() string {
|
||||
func (t timestampMilliType) Precision() string {
|
||||
return PrecisionMillisecond
|
||||
}
|
||||
func (t timestampMilliType) DataType() string {
|
||||
return "timestamp(6)"
|
||||
}
|
||||
|
||||
func (t timestampMicroType) Precision() string {
|
||||
return PrecisionMicrosecond
|
||||
}
|
||||
func (t timestampMicroType) DataType() string {
|
||||
return "timestamp(6)"
|
||||
}
|
||||
|
||||
func (t timestampNanoType) Precision() string {
|
||||
return PrecisionNanosecond
|
||||
}
|
||||
func (t timestampNanoType) DataType() string {
|
||||
return "timestamp(6)"
|
||||
}
|
||||
|
||||
func (t datetimeType) Layout() string {
|
||||
return DateTimeLayout
|
||||
}
|
||||
func (t datetimeType) DataType() string {
|
||||
return "datetime"
|
||||
}
|
||||
|
||||
func (t datetimeMilliType) Layout() string {
|
||||
return DateTimeMilliLayout
|
||||
}
|
||||
func (t datetimeMilliType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t datetimeMicroType) Layout() string {
|
||||
return DateTimeMicroLayout
|
||||
}
|
||||
func (t datetimeMicroType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t datetimeNanoType) Layout() string {
|
||||
return DateTimeNanoLayout
|
||||
}
|
||||
func (t datetimeNanoType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t dateType) Layout() string {
|
||||
return DateLayout
|
||||
}
|
||||
func (t dateType) DataType() string {
|
||||
return "date"
|
||||
}
|
||||
|
||||
func (t dateMilliType) Layout() string {
|
||||
return DateMilliLayout
|
||||
}
|
||||
func (t dateMilliType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t dateMicroType) Layout() string {
|
||||
return DateMicroLayout
|
||||
}
|
||||
func (t dateMicroType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t dateNanoType) Layout() string {
|
||||
return DateNanoLayout
|
||||
}
|
||||
func (t dateNanoType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t timeType) Layout() string {
|
||||
return TimeLayout
|
||||
}
|
||||
func (t timeType) DataType() string {
|
||||
return "time"
|
||||
}
|
||||
|
||||
func (t timeMilliType) Layout() string {
|
||||
return TimeMilliLayout
|
||||
}
|
||||
func (t timeMilliType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t timeMicroType) Layout() string {
|
||||
return TimeMicroLayout
|
||||
}
|
||||
func (t timeMicroType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
func (t timeNanoType) Layout() string {
|
||||
return TimeNanoLayout
|
||||
}
|
||||
func (t timeNanoType) DataType() string {
|
||||
return "datetime(6)"
|
||||
}
|
||||
|
||||
5
vendor/github.com/dromara/carbon/v2/type_carbon.go
generated
vendored
5
vendor/github.com/dromara/carbon/v2/type_carbon.go
generated
vendored
@@ -68,8 +68,3 @@ func (c *Carbon) String() string {
|
||||
}
|
||||
return c.Layout(c.currentLayout)
|
||||
}
|
||||
|
||||
// GormDataType implements "gorm.GormDataTypeInterface" interface for Carbon struct.
|
||||
func (c *Carbon) GormDataType() string {
|
||||
return "datetime"
|
||||
}
|
||||
|
||||
14
vendor/github.com/dromara/carbon/v2/type_format.go
generated
vendored
14
vendor/github.com/dromara/carbon/v2/type_format.go
generated
vendored
@@ -83,20 +83,6 @@ func (t *FormatType[T]) String() string {
|
||||
return t.Format(t.getFormat())
|
||||
}
|
||||
|
||||
// GormDataType implements "gorm.GormDataTypeInterface" interface for FormatType generic struct.
|
||||
func (t *FormatType[T]) GormDataType() string {
|
||||
return t.getDataType()
|
||||
}
|
||||
|
||||
// getDataType returns the data type of FormatType generic struct.
|
||||
func (t *FormatType[T]) getDataType() string {
|
||||
var typer T
|
||||
if v, ok := any(typer).(DataTyper); ok {
|
||||
return v.DataType()
|
||||
}
|
||||
return "datetime"
|
||||
}
|
||||
|
||||
// getFormat returns the format of FormatType generic struct.
|
||||
func (t *FormatType[T]) getFormat() string {
|
||||
var typer T
|
||||
|
||||
14
vendor/github.com/dromara/carbon/v2/type_layout.go
generated
vendored
14
vendor/github.com/dromara/carbon/v2/type_layout.go
generated
vendored
@@ -83,20 +83,6 @@ func (t *LayoutType[T]) String() string {
|
||||
return t.Layout(t.getLayout())
|
||||
}
|
||||
|
||||
// GormDataType implements "gorm.GormDataTypeInterface" interface for LayoutType generic struct.
|
||||
func (t *LayoutType[T]) GormDataType() string {
|
||||
return t.getDataType()
|
||||
}
|
||||
|
||||
// getDataType returns the data type of LayoutType generic struct.
|
||||
func (t *LayoutType[T]) getDataType() string {
|
||||
var typer T
|
||||
if v, ok := any(typer).(DataTyper); ok {
|
||||
return v.DataType()
|
||||
}
|
||||
return "datetime"
|
||||
}
|
||||
|
||||
// getLayout returns the layout of LayoutType generic struct.
|
||||
func (t *LayoutType[T]) getLayout() string {
|
||||
var typer T
|
||||
|
||||
14
vendor/github.com/dromara/carbon/v2/type_timestamp.go
generated
vendored
14
vendor/github.com/dromara/carbon/v2/type_timestamp.go
generated
vendored
@@ -134,20 +134,6 @@ func (t *TimestampType[T]) Int64() (ts int64) {
|
||||
return
|
||||
}
|
||||
|
||||
// GormDataType implements "gorm.GormDataTypeInterface" interface for TimestampType generic struct.
|
||||
func (t *TimestampType[T]) GormDataType() string {
|
||||
return t.getDataType()
|
||||
}
|
||||
|
||||
// getDataType returns data type of TimestampType generic struct.
|
||||
func (t *TimestampType[T]) getDataType() string {
|
||||
var typer T
|
||||
if v, ok := any(typer).(DataTyper); ok {
|
||||
return v.DataType()
|
||||
}
|
||||
return "timestamp"
|
||||
}
|
||||
|
||||
// getPrecision returns precision of TimestampType generic struct.
|
||||
func (t *TimestampType[T]) getPrecision() string {
|
||||
var typer T
|
||||
|
||||
3
vendor/modules.txt
vendored
3
vendor/modules.txt
vendored
@@ -174,10 +174,11 @@ github.com/docker/go-connections/tlsconfig
|
||||
# github.com/docker/go-units v0.5.0
|
||||
## explicit
|
||||
github.com/docker/go-units
|
||||
# github.com/dromara/carbon/v2 v2.6.8
|
||||
# github.com/dromara/carbon/v2 v2.6.11
|
||||
## explicit; go 1.21
|
||||
github.com/dromara/carbon/v2
|
||||
github.com/dromara/carbon/v2/calendar
|
||||
github.com/dromara/carbon/v2/calendar/hebrew
|
||||
github.com/dromara/carbon/v2/calendar/julian
|
||||
github.com/dromara/carbon/v2/calendar/lunar
|
||||
github.com/dromara/carbon/v2/calendar/persian
|
||||
|
||||
Reference in New Issue
Block a user