mirror of
https://github.com/crazy-max/diun.git
synced 2025-12-21 13:23:09 +01:00
Merge pull request #1526 from crazy-max/dependabot/go_modules/github.com/dromara/carbon/v2-2.6.14
chore(deps): bump github.com/dromara/carbon/v2 from 2.6.11 to 2.6.14
This commit is contained in:
12
vendor/github.com/dromara/carbon/v2/.editorconfig
generated
vendored
12
vendor/github.com/dromara/carbon/v2/.editorconfig
generated
vendored
@@ -1,12 +0,0 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
5
vendor/github.com/dromara/carbon/v2/.gitignore
generated
vendored
5
vendor/github.com/dromara/carbon/v2/.gitignore
generated
vendored
@@ -1,5 +0,0 @@
|
||||
# IntelliJ project files
|
||||
.idea
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
177
vendor/github.com/dromara/carbon/v2/.golangci.yml
generated
vendored
177
vendor/github.com/dromara/carbon/v2/.golangci.yml
generated
vendored
@@ -1,177 +0,0 @@
|
||||
---
|
||||
# golangci-lint configuration file made by @ccoVeille
|
||||
# Source: https://github.com/ccoVeille/golangci-lint-config-examples/
|
||||
# Author: @ccoVeille
|
||||
# License: MIT
|
||||
# Variant: 03-safe
|
||||
# Version: v1.2.0
|
||||
#
|
||||
linters:
|
||||
# some linters are enabled by default
|
||||
# https://golangci-lint.run/usage/linters/
|
||||
#
|
||||
# enable some extra linters
|
||||
enable:
|
||||
# Errcheck is a program for checking for unchecked errors in Go code.
|
||||
- errcheck
|
||||
|
||||
# Linter for Go source code that specializes in simplifying code.
|
||||
- gosimple
|
||||
|
||||
# Vet examines Go source code and reports suspicious constructs.
|
||||
- govet
|
||||
|
||||
# Detects when assignments to existing variables are not used.
|
||||
- ineffassign
|
||||
|
||||
# It's a set of rules from staticcheck. See https://staticcheck.io/
|
||||
- staticcheck
|
||||
|
||||
# Fast, configurable, extensible, flexible, and beautiful linter for Go.
|
||||
# Drop-in replacement of golint.
|
||||
- revive
|
||||
|
||||
# check imports order and makes it always deterministic.
|
||||
- gci
|
||||
|
||||
# make sure to use t.Helper() when needed
|
||||
- thelper
|
||||
|
||||
# mirror suggests rewrites to avoid unnecessary []byte/string conversion
|
||||
- mirror
|
||||
|
||||
# detect the possibility to use variables/constants from the Go standard library.
|
||||
- usestdlibvars
|
||||
|
||||
# Finds commonly misspelled English words.
|
||||
- misspell
|
||||
|
||||
# Checks for duplicate words in the source code.
|
||||
- dupword
|
||||
|
||||
# linter to detect errors invalid key values count
|
||||
- loggercheck
|
||||
|
||||
# detects nested contexts in loops or function literals
|
||||
- fatcontext
|
||||
|
||||
# Checks usage of github.com/stretchr/testify/require
|
||||
- testifylint
|
||||
|
||||
linters-settings:
|
||||
gci: # define the section orders for imports
|
||||
sections:
|
||||
# Standard section: captures all standard packages.
|
||||
- standard
|
||||
# Default section: catchall that is not standard or custom
|
||||
- default
|
||||
# linters that related to local tool, so they should be separated
|
||||
- localmodule
|
||||
|
||||
revive:
|
||||
rules:
|
||||
# Check for commonly mistaken usages of the sync/atomic package
|
||||
- name: atomic
|
||||
|
||||
# Blank import should be only in a main or test package, or have a comment justifying it.
|
||||
- name: blank-imports
|
||||
|
||||
# Spots comments not starting with a space
|
||||
- name: comment-spacings
|
||||
|
||||
# context.Context() should be the first parameter of a function when provided as argument.
|
||||
- name: context-as-argument
|
||||
arguments:
|
||||
- allowTypesBefore: "*testing.T"
|
||||
|
||||
# Basic types should not be used as a key in `context.WithValue`
|
||||
- name: context-keys-type
|
||||
|
||||
# warns on some common mistakes when using defer statement.
|
||||
- name: defer
|
||||
|
||||
# Importing with `.` makes the programs much harder to understand
|
||||
- name: dot-imports
|
||||
|
||||
# suggest to simplify if-then-else constructions when possible
|
||||
- name: early-return
|
||||
|
||||
# Empty blocks make code less readable and could be a symptom of a bug or unfinished refactoring.
|
||||
- name: empty-block
|
||||
|
||||
# for better readability, variables of type `error` must be named with the prefix `err`.
|
||||
- name: error-naming
|
||||
|
||||
# for better readability, the errors should be last in the list of returned values by a function.
|
||||
- name: error-return
|
||||
|
||||
# for better readability, error messages should not be capitalized or end with punctuation or a newline.
|
||||
- name: error-strings
|
||||
|
||||
# report when replacing `errors.New(fmt.Sprintf())` with `fmt.Errorf()` is possible
|
||||
- name: errorf
|
||||
|
||||
# Checking if an error is nil to just after return the error or nil is redundant.
|
||||
- name: if-return
|
||||
|
||||
# incrementing an integer variable by 1 is recommended to be done using the `++` operator
|
||||
- name: increment-decrement
|
||||
|
||||
# highlights redundant else-blocks that can be eliminated from the code
|
||||
- name: indent-error-flow
|
||||
|
||||
# This rule suggests a shorter way of writing ranges that do not use the second value.
|
||||
- name: range
|
||||
|
||||
# receiver names in a method should reflect the struct name (p for Person, for example)
|
||||
- name: receiver-naming
|
||||
|
||||
# redefining built in names (true, false, append, make) can lead to bugs very difficult to detect.
|
||||
- name: redefines-builtin-id
|
||||
|
||||
# redundant else-blocks that can be eliminated from the code.
|
||||
- name: superfluous-else
|
||||
|
||||
# prevent confusing name for variables when using `time` package
|
||||
- name: time-naming
|
||||
|
||||
# warns when an exported function or method returns a value of an un-exported type.
|
||||
- name: unexported-return
|
||||
|
||||
# spots and proposes to remove unreachable code. also helps to spot errors
|
||||
- name: unreachable-code
|
||||
|
||||
# Functions or methods with unused parameters can be a symptom of an unfinished refactoring or a bug.
|
||||
- name: unused-parameter
|
||||
|
||||
# warns on useless break statements in case clauses of switch and select statements
|
||||
- name: useless-break
|
||||
|
||||
# report when a variable declaration can be simplified
|
||||
- name: var-declaration
|
||||
|
||||
# warns when initialism, variable or package naming conventions are not followed.
|
||||
- name: var-naming
|
||||
|
||||
dupword:
|
||||
# Keywords used to ignore detection.
|
||||
# Default: []
|
||||
ignore:
|
||||
# - "blah" # this will accept "blah blah …" as a valid duplicate word
|
||||
|
||||
misspell:
|
||||
# Correct spellings using locale preferences for US or UK.
|
||||
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
|
||||
# Default ("") is to use a neutral variety of English.
|
||||
locale: US
|
||||
|
||||
# List of words to ignore
|
||||
# among the one defined in https://github.com/golangci/misspell/blob/master/words.go
|
||||
ignore-words:
|
||||
# - valor
|
||||
# - and
|
||||
|
||||
# Extra word corrections.
|
||||
extra-words:
|
||||
# - typo: "whattever"
|
||||
# correction: "whatever"
|
||||
5
vendor/github.com/dromara/carbon/v2/README.cn.md
generated
vendored
5
vendor/github.com/dromara/carbon/v2/README.cn.md
generated
vendored
@@ -31,7 +31,7 @@
|
||||
|
||||
### 安装使用
|
||||
|
||||
> go version >= 1.21
|
||||
> go version >= 1.18
|
||||
|
||||
```go
|
||||
// 使用 github 库
|
||||
@@ -83,7 +83,7 @@ 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/zh" target="_blank">官方文档</a>,性能测试报告请查看 [分析报告](test_report.cn.md)
|
||||
更多用法示例请查看 <a href="https://carbon.go-pkg.com/zh" target="_blank">官方文档</a>,性能测试报告请查看 [分析报告](docs/BENCHMARK.cn.md)
|
||||
|
||||
## 参考项目
|
||||
|
||||
@@ -102,6 +102,7 @@ carbon.IsTestNow() // false
|
||||
|
||||
<a href="https://github.com/dromara/carbon/graphs/contributors"><img src="https://contrib.rocks/image?repo=dromara/carbon&max=100&columns=16"/></a>
|
||||
|
||||
[如何为 carbon 添加新的本地化语言支持](docs/CONTRIBUTING.cn.md)
|
||||
## 赞助
|
||||
|
||||
`Carbon` 是一个非商业开源项目, 如果你想支持 `Carbon`,
|
||||
|
||||
6
vendor/github.com/dromara/carbon/v2/README.ja.md
generated
vendored
6
vendor/github.com/dromara/carbon/v2/README.ja.md
generated
vendored
@@ -26,7 +26,7 @@
|
||||
## クイックスタート
|
||||
|
||||
### インストール
|
||||
> go version >= 1.21
|
||||
> go version >= 1.18
|
||||
|
||||
```go
|
||||
// github から使う
|
||||
@@ -78,7 +78,7 @@ 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)をご参照ください
|
||||
より多くの使用例については、<a href="https://carbon.go-pkg.com/ja" target="_blank">公式ドキュメント</a>をご覧ください。性能テストレポートについては、[分析レポート](docs/BENCHMARK.ja.md)をご参照ください
|
||||
|
||||
## リファレンス
|
||||
|
||||
@@ -96,6 +96,8 @@ carbon.IsTestNow() // false
|
||||
|
||||
<a href="https://github.com/dromara/carbon/graphs/contributors"><img src="https://contrib.rocks/image?repo=dromara/carbon&max=100&columns=16"/></a>
|
||||
|
||||
[Carbon に新しいローカライズ言語サポートを追加する方法](docs/CONTRIBUTING.ja.md)
|
||||
|
||||
## スポンサー
|
||||
|
||||
`Carbon` は非営利のオープンソースプロジェクトです,`Carbon` をサポートしたい場合は、開発者のために [コーヒーを1杯購入](https://carbon.go-pkg.com/ja/sponsor.html) できます
|
||||
|
||||
6
vendor/github.com/dromara/carbon/v2/README.ko.md
generated
vendored
6
vendor/github.com/dromara/carbon/v2/README.ko.md
generated
vendored
@@ -26,7 +26,7 @@
|
||||
## 빠른 시작
|
||||
|
||||
### 설치
|
||||
> go version >= 1.21
|
||||
> go version >= 1.18
|
||||
|
||||
```go
|
||||
// GitHub를 통해
|
||||
@@ -77,7 +77,7 @@ carbon.ClearTestNow()
|
||||
carbon.IsTestNow() // false
|
||||
```
|
||||
|
||||
더 많은 사용 예시는 <a href="https://carbon.go-pkg.com/ko" target="_blank">공식 문서</a>를 참조하세요. 성능 테스트 보고서는 [분석 보고서](test_report.ko.md)를 참조하세요.
|
||||
더 많은 사용 예시는 <a href="https://carbon.go-pkg.com/ko" target="_blank">공식 문서</a>를 참조하세요. 성능 테스트 보고서는 [분석 보고서](docs/BENCHMARK.ko.md)를 참조하세요.
|
||||
|
||||
## 참고 자료
|
||||
|
||||
@@ -95,6 +95,8 @@ carbon.IsTestNow() // false
|
||||
|
||||
<a href="https://github.com/dromara/carbon/graphs/contributors"><img src="https://contrib.rocks/image?repo=dromara/carbon&max=100&columns=16" /></a>
|
||||
|
||||
[Carbon에 새로운 로컬라이즈드 언어 지원을 추가하는 방법](docs/CONTRIBUTING.ko.md)
|
||||
|
||||
## 스폰서
|
||||
|
||||
`Carbon`은 비상업적 오픈소스 프로젝트입니다. `Carbon`을 지원하고 싶으시다면 개발자에게 [커피 한 잔을 사주세요](https://carbon.go-pkg.com/ko/sponsor.html).
|
||||
|
||||
8
vendor/github.com/dromara/carbon/v2/README.md
generated
vendored
8
vendor/github.com/dromara/carbon/v2/README.md
generated
vendored
@@ -26,7 +26,7 @@ English | [简体中文](README.cn.md) | [日本語](README.ja.md) | [한국어]
|
||||
## Quick Start
|
||||
|
||||
### Installation
|
||||
> go version >= 1.21
|
||||
> go version >= 1.18
|
||||
|
||||
```go
|
||||
// By github
|
||||
@@ -80,9 +80,9 @@ carbon.ClearTestNow()
|
||||
carbon.IsTestNow() // false
|
||||
```
|
||||
|
||||
For more usage examples, please refer to <a href="https://carbon.go-pkg.com/zh" target="_blank">official document</a>.
|
||||
For more usage examples, please refer to <a href="https://carbon.go-pkg.com" target="_blank">official document</a>.
|
||||
|
||||
For performance test reports, please refer to [analysis report](test_report.en.md)
|
||||
For performance test reports, please refer to [benchmark report](docs/BENCHMARK.en.md)
|
||||
|
||||
## References
|
||||
|
||||
@@ -100,6 +100,8 @@ Thanks to all the following who contributed to `Carbon`:
|
||||
|
||||
<a href="https://github.com/dromara/carbon/graphs/contributors"><img src="https://contrib.rocks/image?repo=dromara/carbon&max=100&columns=16" /></a>
|
||||
|
||||
[How to add new localized language support to carbon](docs/CONTRIBUTING.en.md)
|
||||
|
||||
## Sponsors
|
||||
|
||||
`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.
|
||||
|
||||
9
vendor/github.com/dromara/carbon/v2/boundary.go
generated
vendored
9
vendor/github.com/dromara/carbon/v2/boundary.go
generated
vendored
@@ -63,13 +63,8 @@ func (c *Carbon) EndOfQuarter() *Carbon {
|
||||
return c
|
||||
}
|
||||
year, quarter := c.Year(), c.Quarter()
|
||||
var day int
|
||||
switch quarter {
|
||||
case 1, 4:
|
||||
day = MaxDay
|
||||
case 2, 3:
|
||||
day = 30
|
||||
}
|
||||
var quarterDays = [4]int{31, 30, 30, 31} // Q1, Q2, Q3, Q4
|
||||
day := quarterDays[quarter-1]
|
||||
return c.create(year, 3*quarter, day, MaxHour, MaxMinute, MaxSecond, MaxNanosecond)
|
||||
}
|
||||
|
||||
|
||||
2
vendor/github.com/dromara/carbon/v2/calendar.go
generated
vendored
2
vendor/github.com/dromara/carbon/v2/calendar.go
generated
vendored
@@ -90,7 +90,7 @@ func (c *Carbon) Hebrew() *hebrew.Hebrew {
|
||||
func CreateFromHebrew(year, month, day int) *Carbon {
|
||||
h := hebrew.NewHebrew(year, month, day)
|
||||
if h.Error != nil {
|
||||
return &Carbon{isEmpty: true}
|
||||
return &Carbon{Error: h.Error}
|
||||
}
|
||||
return NewCarbon(h.ToGregorian(DefaultTimezone).Time)
|
||||
}
|
||||
|
||||
15
vendor/github.com/dromara/carbon/v2/carbon.go
generated
vendored
15
vendor/github.com/dromara/carbon/v2/carbon.go
generated
vendored
@@ -1,8 +1,8 @@
|
||||
// @Package carbon
|
||||
// @Description a simple, semantic and developer-friendly time package for golang
|
||||
// @Page github.com/dromara/carbon
|
||||
// @Source github.com/dromara/carbon
|
||||
// @Document carbon.go-pkg.com
|
||||
// @Developer gouguoyin
|
||||
// @Blog www.gouguoyin.com
|
||||
// @Email 245629560@qq.com
|
||||
|
||||
// Package carbon is a simple, semantic and developer-friendly time package for golang.
|
||||
@@ -50,12 +50,17 @@ func (c *Carbon) Copy() *Carbon {
|
||||
if c.IsNil() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a deep copy of weekendDays slice to avoid shared reference
|
||||
weekendDays := make([]Weekday, len(c.weekendDays))
|
||||
copy(weekendDays, c.weekendDays)
|
||||
|
||||
return &Carbon{
|
||||
time: time.Date(c.Year(), time.Month(c.Month()), c.Day(), c.Hour(), c.Minute(), c.Second(), c.Nanosecond(), c.loc),
|
||||
time: c.time,
|
||||
weekStartsAt: c.weekStartsAt,
|
||||
weekendDays: c.weekendDays,
|
||||
weekendDays: weekendDays,
|
||||
loc: c.loc,
|
||||
lang: c.lang.Copy(),
|
||||
lang: c.lang,
|
||||
currentLayout: c.currentLayout,
|
||||
isEmpty: c.isEmpty,
|
||||
Error: c.Error,
|
||||
|
||||
156
vendor/github.com/dromara/carbon/v2/comparer.go
generated
vendored
156
vendor/github.com/dromara/carbon/v2/comparer.go
generated
vendored
@@ -67,7 +67,7 @@ func (c *Carbon) IsAM() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("a") == "am"
|
||||
return c.Hour() < 12
|
||||
}
|
||||
|
||||
// IsPM reports whether it is after noon.
|
||||
@@ -75,7 +75,7 @@ func (c *Carbon) IsPM() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("a") == "pm"
|
||||
return c.Hour() >= 12
|
||||
}
|
||||
|
||||
// IsLeapYear reports whether it is a leap year.
|
||||
@@ -84,10 +84,7 @@ func (c *Carbon) IsLeapYear() bool {
|
||||
return false
|
||||
}
|
||||
year := c.Year()
|
||||
if year%400 == 0 || (year%4 == 0 && year%100 != 0) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return year%400 == 0 || (year%4 == 0 && year%100 != 0)
|
||||
}
|
||||
|
||||
// IsLongYear reports whether it is a long year,
|
||||
@@ -103,154 +100,97 @@ func (c *Carbon) IsLongYear() bool {
|
||||
|
||||
// IsJanuary reports whether it is January.
|
||||
func (c *Carbon) IsJanuary() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.January)
|
||||
return c.isMonth(time.January)
|
||||
}
|
||||
|
||||
// IsFebruary reports whether it is February.
|
||||
func (c *Carbon) IsFebruary() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.February)
|
||||
return c.isMonth(time.February)
|
||||
}
|
||||
|
||||
// IsMarch reports whether it is March.
|
||||
func (c *Carbon) IsMarch() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.March)
|
||||
return c.isMonth(time.March)
|
||||
}
|
||||
|
||||
// IsApril reports whether it is April.
|
||||
func (c *Carbon) IsApril() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.April)
|
||||
return c.isMonth(time.April)
|
||||
}
|
||||
|
||||
// IsMay reports whether it is May.
|
||||
func (c *Carbon) IsMay() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.May)
|
||||
return c.isMonth(time.May)
|
||||
}
|
||||
|
||||
// IsJune reports whether it is June.
|
||||
func (c *Carbon) IsJune() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.June)
|
||||
return c.isMonth(time.June)
|
||||
}
|
||||
|
||||
// IsJuly reports whether it is July.
|
||||
func (c *Carbon) IsJuly() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.July)
|
||||
return c.isMonth(time.July)
|
||||
}
|
||||
|
||||
// IsAugust reports whether it is August.
|
||||
func (c *Carbon) IsAugust() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.August)
|
||||
return c.isMonth(time.August)
|
||||
}
|
||||
|
||||
// IsSeptember reports whether it is September.
|
||||
func (c *Carbon) IsSeptember() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.September)
|
||||
return c.isMonth(time.September)
|
||||
}
|
||||
|
||||
// IsOctober reports whether it is October.
|
||||
func (c *Carbon) IsOctober() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.October)
|
||||
return c.isMonth(time.October)
|
||||
}
|
||||
|
||||
// IsNovember reports whether it is November.
|
||||
func (c *Carbon) IsNovember() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.November)
|
||||
return c.isMonth(time.November)
|
||||
}
|
||||
|
||||
// IsDecember reports whether it is December.
|
||||
func (c *Carbon) IsDecember() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Month() == int(time.December)
|
||||
return c.isMonth(time.December)
|
||||
}
|
||||
|
||||
// IsMonday reports whether it is Monday.
|
||||
func (c *Carbon) IsMonday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Monday
|
||||
return c.isWeekday(time.Monday)
|
||||
}
|
||||
|
||||
// IsTuesday reports whether it is Tuesday.
|
||||
func (c *Carbon) IsTuesday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Tuesday
|
||||
return c.isWeekday(time.Tuesday)
|
||||
}
|
||||
|
||||
// IsWednesday reports whether it is Wednesday.
|
||||
func (c *Carbon) IsWednesday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Wednesday
|
||||
return c.isWeekday(time.Wednesday)
|
||||
}
|
||||
|
||||
// IsThursday reports whether it is Thursday.
|
||||
func (c *Carbon) IsThursday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Thursday
|
||||
return c.isWeekday(time.Thursday)
|
||||
}
|
||||
|
||||
// IsFriday reports whether it is Friday.
|
||||
func (c *Carbon) IsFriday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Friday
|
||||
return c.isWeekday(time.Friday)
|
||||
}
|
||||
|
||||
// IsSaturday reports whether it is Saturday.
|
||||
func (c *Carbon) IsSaturday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Saturday
|
||||
return c.isWeekday(time.Saturday)
|
||||
}
|
||||
|
||||
// IsSunday reports whether it is Sunday.
|
||||
func (c *Carbon) IsSunday() bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == time.Sunday
|
||||
return c.isWeekday(time.Sunday)
|
||||
}
|
||||
|
||||
// IsWeekday reports whether it is weekday.
|
||||
@@ -366,7 +306,9 @@ func (c *Carbon) IsSameMonth(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("Ym") == t.Format("Ym")
|
||||
cTime := c.StdTime()
|
||||
tTime := t.StdTime()
|
||||
return cTime.Year() == tTime.Year() && cTime.Month() == tTime.Month()
|
||||
}
|
||||
|
||||
// IsSameDay reports whether it is same day.
|
||||
@@ -374,7 +316,11 @@ func (c *Carbon) IsSameDay(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("Ymd") == t.Format("Ymd")
|
||||
cTime := c.StdTime()
|
||||
tTime := t.StdTime()
|
||||
return cTime.Year() == tTime.Year() &&
|
||||
cTime.Month() == tTime.Month() &&
|
||||
cTime.Day() == tTime.Day()
|
||||
}
|
||||
|
||||
// IsSameHour reports whether it is same hour.
|
||||
@@ -382,7 +328,12 @@ func (c *Carbon) IsSameHour(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("YmdH") == t.Format("YmdH")
|
||||
cTime := c.StdTime()
|
||||
tTime := t.StdTime()
|
||||
return cTime.Year() == tTime.Year() &&
|
||||
cTime.Month() == tTime.Month() &&
|
||||
cTime.Day() == tTime.Day() &&
|
||||
cTime.Hour() == tTime.Hour()
|
||||
}
|
||||
|
||||
// IsSameMinute reports whether it is same minute.
|
||||
@@ -390,7 +341,13 @@ func (c *Carbon) IsSameMinute(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("YmdHi") == t.Format("YmdHi")
|
||||
cTime := c.StdTime()
|
||||
tTime := t.StdTime()
|
||||
return cTime.Year() == tTime.Year() &&
|
||||
cTime.Month() == tTime.Month() &&
|
||||
cTime.Day() == tTime.Day() &&
|
||||
cTime.Hour() == tTime.Hour() &&
|
||||
cTime.Minute() == tTime.Minute()
|
||||
}
|
||||
|
||||
// IsSameSecond reports whether it is same second.
|
||||
@@ -398,7 +355,14 @@ func (c *Carbon) IsSameSecond(t *Carbon) bool {
|
||||
if c.IsInvalid() || t.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.Format("YmdHis") == t.Format("YmdHis")
|
||||
cTime := c.StdTime()
|
||||
tTime := t.StdTime()
|
||||
return cTime.Year() == tTime.Year() &&
|
||||
cTime.Month() == tTime.Month() &&
|
||||
cTime.Day() == tTime.Day() &&
|
||||
cTime.Hour() == tTime.Hour() &&
|
||||
cTime.Minute() == tTime.Minute() &&
|
||||
cTime.Second() == tTime.Second()
|
||||
}
|
||||
|
||||
// Compare compares by an operator.
|
||||
@@ -535,3 +499,21 @@ func (c *Carbon) BetweenIncludedBoth(start *Carbon, end *Carbon) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isMonth reports whether the current month matches the given month.
|
||||
// It returns false if the Carbon instance is invalid.
|
||||
func (c *Carbon) isMonth(month time.Month) bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Month() == month
|
||||
}
|
||||
|
||||
// isWeekday reports whether the current weekday matches the given weekday.
|
||||
// It returns false if the Carbon instance is invalid.
|
||||
func (c *Carbon) isWeekday(weekday time.Weekday) bool {
|
||||
if c.IsInvalid() {
|
||||
return false
|
||||
}
|
||||
return c.StdTime().Weekday() == weekday
|
||||
}
|
||||
|
||||
2
vendor/github.com/dromara/carbon/v2/constants.go
generated
vendored
2
vendor/github.com/dromara/carbon/v2/constants.go
generated
vendored
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
// Version current version
|
||||
const Version = "2.6.11"
|
||||
const Version = "2.6.14"
|
||||
|
||||
// timezone constants
|
||||
const (
|
||||
|
||||
12
vendor/github.com/dromara/carbon/v2/constellation.go
generated
vendored
12
vendor/github.com/dromara/carbon/v2/constellation.go
generated
vendored
@@ -27,6 +27,12 @@ func (c *Carbon) Constellation() string {
|
||||
if c.IsInvalid() {
|
||||
return ""
|
||||
}
|
||||
|
||||
lang := c.lang
|
||||
if lang == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
index := -1
|
||||
_, month, day := c.Date()
|
||||
for i := 0; i < len(constellations); i++ {
|
||||
@@ -39,10 +45,10 @@ func (c *Carbon) Constellation() string {
|
||||
}
|
||||
}
|
||||
|
||||
c.lang.rw.RLock()
|
||||
defer c.lang.rw.RUnlock()
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
if resources, ok := c.lang.resources["constellations"]; ok {
|
||||
if resources, ok := lang.resources["constellations"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == MonthsPerYear {
|
||||
return slice[index]
|
||||
|
||||
200
vendor/github.com/dromara/carbon/v2/difference.go
generated
vendored
200
vendor/github.com/dromara/carbon/v2/difference.go
generated
vendored
@@ -1,15 +1,13 @@
|
||||
package carbon
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DiffInYears gets the difference in years.
|
||||
func (c *Carbon) DiffInYears(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -21,14 +19,18 @@ func (c *Carbon) DiffInYears(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
dy, dm, dd := end.Year()-start.Year(), end.Month()-start.Month(), end.Day()-start.Day()
|
||||
if dm < 0 || (dm == 0 && dd < 0) {
|
||||
dy--
|
||||
sign := int64(1)
|
||||
s, e := c, end
|
||||
if e.Lt(s) {
|
||||
s, e = e, s
|
||||
sign = -1
|
||||
}
|
||||
if dy < 0 && (dd != 0 || dm != 0) {
|
||||
dy++
|
||||
|
||||
years := e.Year() - s.Year()
|
||||
if s.StdTime().AddDate(years, 0, 0).After(e.StdTime()) {
|
||||
years--
|
||||
}
|
||||
return int64(dy)
|
||||
return int64(years) * sign
|
||||
}
|
||||
|
||||
// DiffAbsInYears gets the difference in years with absolute value.
|
||||
@@ -38,8 +40,7 @@ func (c *Carbon) DiffAbsInYears(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInMonths gets the difference in months.
|
||||
func (c *Carbon) DiffInMonths(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -51,17 +52,17 @@ func (c *Carbon) DiffInMonths(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
if start.Month() == end.Month() && start.Year() == end.Year() {
|
||||
return 0
|
||||
}
|
||||
dd := start.DiffInDays(end)
|
||||
sign := 1
|
||||
if dd <= 0 {
|
||||
start, end = end, start
|
||||
sign := int64(1)
|
||||
s, e := c, end
|
||||
if e.Lt(s) {
|
||||
s, e = e, s
|
||||
sign = -1
|
||||
}
|
||||
months := getDiffInMonths(start, end)
|
||||
return months * int64(sign)
|
||||
months := (e.Year()-s.Year())*12 + (e.Month() - s.Month())
|
||||
if s.StdTime().AddDate(0, months, 0).After(e.StdTime()) {
|
||||
months--
|
||||
}
|
||||
return int64(months) * sign
|
||||
}
|
||||
|
||||
// DiffAbsInMonths gets the difference in months with absolute value.
|
||||
@@ -71,8 +72,7 @@ func (c *Carbon) DiffAbsInMonths(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInWeeks gets the difference in weeks.
|
||||
func (c *Carbon) DiffInWeeks(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -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()) / (DaysPerWeek * HoursPerDay * SecondsPerHour))))
|
||||
return (end.Timestamp() - c.Timestamp()) / SecondsPerWeek
|
||||
}
|
||||
|
||||
// DiffAbsInWeeks gets the difference in weeks with absolute value.
|
||||
@@ -94,8 +94,7 @@ func (c *Carbon) DiffAbsInWeeks(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInDays gets the difference in days.
|
||||
func (c *Carbon) DiffInDays(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -107,7 +106,7 @@ func (c *Carbon) DiffInDays(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return int64(math.Floor(float64((end.Timestamp() - start.Timestamp()) / (HoursPerDay * SecondsPerHour))))
|
||||
return (end.Timestamp() - c.Timestamp()) / SecondsPerDay
|
||||
}
|
||||
|
||||
// DiffAbsInDays gets the difference in days with absolute value.
|
||||
@@ -117,8 +116,7 @@ func (c *Carbon) DiffAbsInDays(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInHours gets the difference in hours.
|
||||
func (c *Carbon) DiffInHours(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -130,7 +128,7 @@ func (c *Carbon) DiffInHours(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return start.DiffInSeconds(end) / SecondsPerHour
|
||||
return c.DiffInSeconds(end) / SecondsPerHour
|
||||
}
|
||||
|
||||
// DiffAbsInHours gets the difference in hours with absolute value.
|
||||
@@ -140,8 +138,7 @@ func (c *Carbon) DiffAbsInHours(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInMinutes gets the difference in minutes.
|
||||
func (c *Carbon) DiffInMinutes(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -153,7 +150,7 @@ func (c *Carbon) DiffInMinutes(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return start.DiffInSeconds(end) / SecondsPerMinute
|
||||
return c.DiffInSeconds(end) / SecondsPerMinute
|
||||
}
|
||||
|
||||
// DiffAbsInMinutes gets the difference in minutes with absolute value.
|
||||
@@ -163,8 +160,7 @@ func (c *Carbon) DiffAbsInMinutes(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInSeconds gets the difference in seconds.
|
||||
func (c *Carbon) DiffInSeconds(carbon ...*Carbon) int64 {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -176,7 +172,7 @@ func (c *Carbon) DiffInSeconds(carbon ...*Carbon) int64 {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return end.Timestamp() - start.Timestamp()
|
||||
return end.Timestamp() - c.Timestamp()
|
||||
}
|
||||
|
||||
// DiffAbsInSeconds gets the difference in seconds with absolute value.
|
||||
@@ -186,8 +182,7 @@ func (c *Carbon) DiffAbsInSeconds(carbon ...*Carbon) int64 {
|
||||
|
||||
// DiffInString gets the difference in string, i18n is supported.
|
||||
func (c *Carbon) DiffInString(carbon ...*Carbon) string {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() || c.lang == nil {
|
||||
return ""
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -199,14 +194,13 @@ func (c *Carbon) DiffInString(carbon ...*Carbon) string {
|
||||
if end.IsInvalid() {
|
||||
return ""
|
||||
}
|
||||
unit, value := start.diff(end)
|
||||
unit, value := c.diff(end)
|
||||
return c.lang.translate(unit, value)
|
||||
}
|
||||
|
||||
// DiffAbsInString gets the difference in string with absolute value, i18n is supported.
|
||||
func (c *Carbon) DiffAbsInString(carbon ...*Carbon) string {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() || c.lang == nil {
|
||||
return ""
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -218,14 +212,13 @@ func (c *Carbon) DiffAbsInString(carbon ...*Carbon) string {
|
||||
if end.IsInvalid() {
|
||||
return ""
|
||||
}
|
||||
unit, value := start.diff(end)
|
||||
unit, value := c.diff(end)
|
||||
return c.lang.translate(unit, getAbsValue(value))
|
||||
}
|
||||
|
||||
// DiffInDuration gets the difference in duration.
|
||||
func (c *Carbon) DiffInDuration(carbon ...*Carbon) Duration {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
var end *Carbon
|
||||
@@ -237,7 +230,7 @@ func (c *Carbon) DiffInDuration(carbon ...*Carbon) Duration {
|
||||
if end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
return end.StdTime().Sub(start.StdTime())
|
||||
return end.StdTime().Sub(c.StdTime())
|
||||
}
|
||||
|
||||
// DiffAbsInDuration gets the difference in duration with absolute value.
|
||||
@@ -247,75 +240,108 @@ func (c *Carbon) DiffAbsInDuration(carbon ...*Carbon) Duration {
|
||||
|
||||
// DiffForHumans gets the difference in a human-readable format, i18n is supported.
|
||||
func (c *Carbon) DiffForHumans(carbon ...*Carbon) string {
|
||||
start := c
|
||||
if start.IsInvalid() {
|
||||
if c.IsInvalid() || c.lang == nil {
|
||||
return ""
|
||||
}
|
||||
var end *Carbon
|
||||
if len(carbon) > 0 {
|
||||
end = carbon[0]
|
||||
} else {
|
||||
end = Now().SetLocation(c.loc)
|
||||
}
|
||||
end := func() *Carbon {
|
||||
if len(carbon) > 0 {
|
||||
return carbon[0]
|
||||
}
|
||||
return Now().SetLocation(c.loc)
|
||||
}()
|
||||
if end.IsInvalid() {
|
||||
return ""
|
||||
}
|
||||
unit, value := start.diff(end)
|
||||
|
||||
unit, value := c.diff(end)
|
||||
translation := c.lang.translate(unit, getAbsValue(value))
|
||||
if unit == "now" {
|
||||
return translation
|
||||
}
|
||||
if c.Lt(end) && len(carbon) == 0 {
|
||||
return strings.Replace(c.lang.resources["ago"], "%s", translation, 1)
|
||||
|
||||
// Concurrent-safe access to language resources
|
||||
c.lang.rw.RLock()
|
||||
resources := c.lang.resources
|
||||
ago := resources["ago"]
|
||||
before := resources["before"]
|
||||
fromNow := resources["from_now"]
|
||||
after := resources["after"]
|
||||
c.lang.rw.RUnlock()
|
||||
|
||||
isBefore := value > 0
|
||||
if isBefore && len(carbon) == 0 {
|
||||
return strings.Replace(ago, "%s", translation, 1)
|
||||
}
|
||||
if c.Lt(end) && len(carbon) > 0 {
|
||||
return strings.Replace(c.lang.resources["before"], "%s", translation, 1)
|
||||
if isBefore && len(carbon) > 0 {
|
||||
return strings.Replace(before, "%s", translation, 1)
|
||||
}
|
||||
if c.Gt(end) && len(carbon) == 0 {
|
||||
return strings.Replace(c.lang.resources["from_now"], "%s", translation, 1)
|
||||
if !isBefore && len(carbon) == 0 {
|
||||
return strings.Replace(fromNow, "%s", translation, 1)
|
||||
}
|
||||
return strings.Replace(c.lang.resources["after"], "%s", translation, 1)
|
||||
return strings.Replace(after, "%s", translation, 1)
|
||||
}
|
||||
|
||||
// gets the difference for unit and value.
|
||||
func (c *Carbon) diff(end *Carbon) (unit string, value int64) {
|
||||
switch true {
|
||||
case c.DiffAbsInYears(end) > 0:
|
||||
unit = "year"
|
||||
value = c.DiffInYears(end)
|
||||
case c.DiffAbsInMonths(end) > 0:
|
||||
unit = "month"
|
||||
value = c.DiffInMonths(end)
|
||||
case c.DiffAbsInWeeks(end) > 0:
|
||||
unit = "week"
|
||||
value = c.DiffInWeeks(end)
|
||||
case c.DiffAbsInDays(end) > 0:
|
||||
unit = "day"
|
||||
value = c.DiffInDays(end)
|
||||
case c.DiffAbsInHours(end) > 0:
|
||||
unit = "hour"
|
||||
value = c.DiffInHours(end)
|
||||
case c.DiffAbsInMinutes(end) > 0:
|
||||
unit = "minute"
|
||||
value = c.DiffInMinutes(end)
|
||||
case c.DiffAbsInSeconds(end) > 0:
|
||||
unit = "second"
|
||||
value = c.DiffInSeconds(end)
|
||||
case c.DiffAbsInSeconds(end) == 0:
|
||||
unit = "now"
|
||||
value = 0
|
||||
// Years
|
||||
diffYears := c.DiffInYears(end)
|
||||
if getAbsValue(diffYears) > 0 {
|
||||
return "year", diffYears
|
||||
}
|
||||
return
|
||||
|
||||
// Months
|
||||
diffMonths := c.DiffInMonths(end)
|
||||
if getAbsValue(diffMonths) > 0 {
|
||||
return "month", diffMonths
|
||||
}
|
||||
|
||||
// Weeks
|
||||
diffWeeks := c.DiffInWeeks(end)
|
||||
if getAbsValue(diffWeeks) > 0 {
|
||||
return "week", diffWeeks
|
||||
}
|
||||
|
||||
// Days
|
||||
diffDays := c.DiffInDays(end)
|
||||
if getAbsValue(diffDays) > 0 {
|
||||
return "day", diffDays
|
||||
}
|
||||
|
||||
// Hours
|
||||
diffHours := c.DiffInHours(end)
|
||||
if getAbsValue(diffHours) > 0 {
|
||||
return "hour", diffHours
|
||||
}
|
||||
|
||||
// Minutes
|
||||
diffMinutes := c.DiffInMinutes(end)
|
||||
if getAbsValue(diffMinutes) > 0 {
|
||||
return "minute", diffMinutes
|
||||
}
|
||||
|
||||
// Seconds
|
||||
diffSeconds := c.DiffInSeconds(end)
|
||||
if getAbsValue(diffSeconds) > 0 {
|
||||
return "second", diffSeconds
|
||||
}
|
||||
|
||||
return "now", 0
|
||||
}
|
||||
|
||||
// gets the difference in months.
|
||||
// Nil and invalid inputs return 0 to match existing tests.
|
||||
func getDiffInMonths(start, end *Carbon) int64 {
|
||||
if start == nil || end == nil {
|
||||
return 0
|
||||
}
|
||||
if start.IsInvalid() || end.IsInvalid() {
|
||||
return 0
|
||||
}
|
||||
sy, sm, d, h, i, s, ns := start.DateTimeNano()
|
||||
ey, em, _ := end.Date()
|
||||
dm := (ey-sy)*12 + (em - sm)
|
||||
if time.Date(sy, time.Month(sm+dm), d, h, i, s, ns, start.StdTime().Location()).After(end.StdTime()) {
|
||||
loc := start.StdTime().Location()
|
||||
if time.Date(sy, time.Month(sm+dm), d, h, i, s, ns, loc).After(end.StdTime()) {
|
||||
return int64(dm - 1)
|
||||
}
|
||||
return int64(dm)
|
||||
|
||||
5
vendor/github.com/dromara/carbon/v2/errors.go
generated
vendored
5
vendor/github.com/dromara/carbon/v2/errors.go
generated
vendored
@@ -50,11 +50,6 @@ var (
|
||||
return fmt.Errorf("resources cannot be empty")
|
||||
}
|
||||
|
||||
// ErrInvalidResourcesError invalid resources error.
|
||||
ErrInvalidResourcesError = func(resources map[string]string) error {
|
||||
return fmt.Errorf("invalid resources %v", resources)
|
||||
}
|
||||
|
||||
// ErrEmptyTimezone empty timezone error.
|
||||
ErrEmptyTimezone = func() error {
|
||||
return fmt.Errorf("timezone cannot be empty")
|
||||
|
||||
56
vendor/github.com/dromara/carbon/v2/extremum.go
generated
vendored
56
vendor/github.com/dromara/carbon/v2/extremum.go
generated
vendored
@@ -41,17 +41,24 @@ func MinDuration() Duration {
|
||||
|
||||
// Max returns the maximum Carbon instance from some given Carbon instances.
|
||||
func Max(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
|
||||
c = c1
|
||||
if c.IsInvalid() {
|
||||
return
|
||||
// If first carbon is invalid, return it immediately
|
||||
if c1.IsInvalid() {
|
||||
return c1
|
||||
}
|
||||
|
||||
c = c1
|
||||
// If no additional arguments, return the first one
|
||||
if len(c2) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Check all additional arguments
|
||||
for _, carbon := range c2 {
|
||||
// If any carbon is invalid, return it immediately
|
||||
if carbon.IsInvalid() {
|
||||
return carbon
|
||||
}
|
||||
// Update maximum if current carbon is greater or equal
|
||||
if carbon.Gte(c) {
|
||||
c = carbon
|
||||
}
|
||||
@@ -61,17 +68,24 @@ func Max(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
|
||||
|
||||
// Min returns the minimum Carbon instance from some given Carbon instances.
|
||||
func Min(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
|
||||
c = c1
|
||||
if c.IsInvalid() {
|
||||
return
|
||||
// If first carbon is invalid, return it immediately
|
||||
if c1.IsInvalid() {
|
||||
return c1
|
||||
}
|
||||
|
||||
c = c1
|
||||
// If no additional arguments, return the first one
|
||||
if len(c2) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// Check all additional arguments
|
||||
for _, carbon := range c2 {
|
||||
// If any carbon is invalid, return it immediately
|
||||
if carbon.IsInvalid() {
|
||||
return carbon
|
||||
}
|
||||
// Update minimum if current carbon is less or equal
|
||||
if carbon.Lte(c) {
|
||||
c = carbon
|
||||
}
|
||||
@@ -81,23 +95,34 @@ func Min(c1 *Carbon, c2 ...*Carbon) (c *Carbon) {
|
||||
|
||||
// Closest returns the closest Carbon instance from some given Carbon instances.
|
||||
func (c *Carbon) Closest(c1 *Carbon, c2 ...*Carbon) *Carbon {
|
||||
// Validate the base carbon instance
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
|
||||
// Validate the first comparison instance
|
||||
if c1.IsInvalid() {
|
||||
return c1
|
||||
}
|
||||
|
||||
// If no additional arguments, return the first one
|
||||
if len(c2) == 0 {
|
||||
return c1
|
||||
}
|
||||
|
||||
// Find the closest among all instances
|
||||
closest := c1
|
||||
minDiff := c.DiffAbsInSeconds(closest)
|
||||
|
||||
// Check all additional arguments
|
||||
for _, arg := range c2 {
|
||||
// Validate each argument
|
||||
if arg.IsInvalid() {
|
||||
return arg
|
||||
}
|
||||
diff := c.DiffAbsInSeconds(arg)
|
||||
if diff < minDiff {
|
||||
|
||||
// Calculate difference and update if closer
|
||||
if diff := c.DiffAbsInSeconds(arg); diff < minDiff {
|
||||
minDiff = diff
|
||||
closest = arg
|
||||
}
|
||||
@@ -107,23 +132,34 @@ func (c *Carbon) Closest(c1 *Carbon, c2 ...*Carbon) *Carbon {
|
||||
|
||||
// Farthest returns the farthest Carbon instance from some given Carbon instances.
|
||||
func (c *Carbon) Farthest(c1 *Carbon, c2 ...*Carbon) *Carbon {
|
||||
// Validate the base carbon instance
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
|
||||
// Validate the first comparison instance
|
||||
if c1.IsInvalid() {
|
||||
return c1
|
||||
}
|
||||
|
||||
// If no additional arguments, return the first one
|
||||
if len(c2) == 0 {
|
||||
return c1
|
||||
}
|
||||
|
||||
// Find the farthest among all instances
|
||||
farthest := c1
|
||||
maxDiff := c.DiffAbsInSeconds(farthest)
|
||||
|
||||
// Check all additional arguments
|
||||
for _, arg := range c2 {
|
||||
// Validate each argument
|
||||
if arg.IsInvalid() {
|
||||
return arg
|
||||
}
|
||||
diff := c.DiffAbsInSeconds(arg)
|
||||
if diff > maxDiff {
|
||||
|
||||
// Calculate difference and update if farther
|
||||
if diff := c.DiffAbsInSeconds(arg); diff > maxDiff {
|
||||
maxDiff = diff
|
||||
farthest = arg
|
||||
}
|
||||
|
||||
8
vendor/github.com/dromara/carbon/v2/frozen.go
generated
vendored
8
vendor/github.com/dromara/carbon/v2/frozen.go
generated
vendored
@@ -21,18 +21,18 @@ func SetTestNow(c *Carbon) {
|
||||
}
|
||||
|
||||
frozenNow.rw.Lock()
|
||||
frozenNow.testNow = c
|
||||
frozenNow.rw.Unlock()
|
||||
defer frozenNow.rw.Unlock()
|
||||
|
||||
frozenNow.testNow = c
|
||||
atomic.StoreInt32(&frozenNow.isFrozen, 1)
|
||||
}
|
||||
|
||||
// ClearTestNow clears the test Carbon instance for now.
|
||||
func ClearTestNow() {
|
||||
frozenNow.rw.Lock()
|
||||
frozenNow.testNow = nil
|
||||
frozenNow.rw.Unlock()
|
||||
defer frozenNow.rw.Unlock()
|
||||
|
||||
frozenNow.testNow = nil
|
||||
atomic.StoreInt32(&frozenNow.isFrozen, 0)
|
||||
}
|
||||
|
||||
|
||||
3
vendor/github.com/dromara/carbon/v2/getter.go
generated
vendored
3
vendor/github.com/dromara/carbon/v2/getter.go
generated
vendored
@@ -370,6 +370,9 @@ func (c *Carbon) Locale() string {
|
||||
if c.IsInvalid() {
|
||||
return ""
|
||||
}
|
||||
if c.lang == nil {
|
||||
return ""
|
||||
}
|
||||
return c.lang.locale
|
||||
}
|
||||
|
||||
|
||||
74
vendor/github.com/dromara/carbon/v2/helper.go
generated
vendored
74
vendor/github.com/dromara/carbon/v2/helper.go
generated
vendored
@@ -1,9 +1,8 @@
|
||||
package carbon
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -86,57 +85,104 @@ var defaultLayouts = []string{
|
||||
"20060102150405Z07:00", "20060102150405.999999999Z07:00",
|
||||
}
|
||||
|
||||
// layoutCache caches format to layout conversions to avoid repeated parsing
|
||||
var layoutCache sync.Map
|
||||
|
||||
// converts format to layout.
|
||||
func format2layout(format string) string {
|
||||
buffer := &bytes.Buffer{}
|
||||
// Check cache first
|
||||
if cached, exists := layoutCache.Load(format); exists {
|
||||
return cached.(string)
|
||||
}
|
||||
|
||||
// Pre-allocate buffer with estimated capacity to reduce allocations
|
||||
estimatedSize := len(format) * 2
|
||||
buffer := make([]byte, 0, estimatedSize)
|
||||
|
||||
for i := 0; i < len(format); i++ {
|
||||
if layout, ok := formatMap[format[i]]; ok {
|
||||
buffer.WriteString(layout)
|
||||
buffer = append(buffer, layout...)
|
||||
} else {
|
||||
switch format[i] {
|
||||
case '\\': // raw output, no parse
|
||||
buffer.WriteByte(format[i+1])
|
||||
i++
|
||||
// Ensure we don't go out of bounds
|
||||
if i+1 < len(format) {
|
||||
buffer = append(buffer, format[i+1])
|
||||
i++
|
||||
}
|
||||
continue
|
||||
default:
|
||||
buffer.WriteByte(format[i])
|
||||
buffer = append(buffer, format[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
|
||||
result := string(buffer)
|
||||
|
||||
// Cache the result for common formats to improve performance
|
||||
// Only cache reasonably short formats to avoid memory bloat
|
||||
if len(format) <= 50 {
|
||||
layoutCache.Store(format, result)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// timezoneCache caches parsed timezone locations to avoid repeated parsing
|
||||
var timezoneCache sync.Map
|
||||
|
||||
// parses a timezone string as a time.Location instance.
|
||||
func parseTimezone(timezone string) (loc *Location, err error) {
|
||||
if timezone == "" {
|
||||
return nil, ErrEmptyTimezone()
|
||||
}
|
||||
|
||||
// Check cache first
|
||||
if cached, exists := timezoneCache.Load(timezone); exists {
|
||||
return cached.(*Location), nil
|
||||
}
|
||||
|
||||
if loc, err = time.LoadLocation(timezone); err != nil {
|
||||
err = fmt.Errorf("%w: %w", ErrInvalidTimezone(timezone), err)
|
||||
return
|
||||
}
|
||||
|
||||
// Cache the successful result
|
||||
timezoneCache.Store(timezone, loc)
|
||||
return
|
||||
}
|
||||
|
||||
// durationCache caches parsed durations to avoid repeated parsing
|
||||
var durationCache sync.Map
|
||||
|
||||
// parses a duration string as a time.Duration instance.
|
||||
func parseDuration(duration string) (dur Duration, err error) {
|
||||
if duration == "" {
|
||||
return 0, ErrEmptyDuration()
|
||||
}
|
||||
|
||||
// Check cache first for common durations
|
||||
if cached, exists := durationCache.Load(duration); exists {
|
||||
return cached.(Duration), nil
|
||||
}
|
||||
|
||||
if dur, err = time.ParseDuration(duration); err != nil {
|
||||
err = fmt.Errorf("%w: %w", ErrInvalidDuration(duration), err)
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// parses a timestamp string as a int64 format timestamp.
|
||||
func parseTimestamp(timestamp string) (ts int64, err error) {
|
||||
if ts, err = strconv.ParseInt(timestamp, 10, 64); err != nil {
|
||||
err = fmt.Errorf("%w: %w", ErrInvalidTimestamp(timestamp), err)
|
||||
// Cache the successful result for common durations
|
||||
// Only cache reasonably short durations to avoid memory bloat
|
||||
if len(duration) <= 20 {
|
||||
durationCache.Store(duration, dur)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// gets absolute value.
|
||||
func getAbsValue(value int64) int64 {
|
||||
// Use bit manipulation for better performance
|
||||
// For positive numbers: value ^ 0 - 0 = value
|
||||
// For negative numbers: value ^ -1 - (-1) = ^value + 1 = -value
|
||||
return (value ^ (value >> 63)) - (value >> 63)
|
||||
}
|
||||
|
||||
24
vendor/github.com/dromara/carbon/v2/lang/el.json
generated
vendored
Normal file
24
vendor/github.com/dromara/carbon/v2/lang/el.json
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "Greek",
|
||||
"author": "https://cursor.com/",
|
||||
"months": "Ιανουάριος|Φεβρουάριος|Μάρτιος|Απρίλιος|Μάιος|Ιούνιος|Ιούλιος|Αύγουστος|Σεπτέμβριος|Οκτώβριος|Νοέμβριος|Δεκέμβριος",
|
||||
"short_months": "Ιαν|Φεβ|Μαρ|Απρ|Μάι|Ιουν|Ιουλ|Αυγ|Σεπ|Οκτ|Νοε|Δεκ",
|
||||
"weeks": "Κυριακή|Δευτέρα|Τρίτη|Τετάρτη|Πέμπτη|Παρασκευή|Σάββατο",
|
||||
"short_weeks": "Κυρ|Δευ|Τρι|Τετ|Πεμ|Παρ|Σαβ",
|
||||
"seasons": "Άνοιξη|Καλοκαίρι|Φθινόπωρο|Χειμώνας",
|
||||
"constellations": "Κριός|Ταύρος|Δίδυμοι|Καρκίνος|Λέων|Παρθένος|Ζυγός|Σκορπιός|Τοξότης|Αιγόκερως|Υδροχόος|Ιχθύες",
|
||||
"year": "1 χρόνος|%d χρόνια",
|
||||
"month": "1 μήνας|%d μήνες",
|
||||
"week": "1 εβδομάδα|%d εβδομάδες",
|
||||
"day": "1 ημέρα|%d ημέρες",
|
||||
"hour": "1 ώρα|%d ώρες",
|
||||
"minute": "1 λεπτό|%d λεπτά",
|
||||
"second": "1 δευτερόλεπτο|%d δευτερόλεπτα",
|
||||
"now": "μόλις τώρα",
|
||||
"ago": "%s πριν",
|
||||
"from_now": "σε %s",
|
||||
"before": "%s πριν",
|
||||
"after": "%s μετά"
|
||||
}
|
||||
|
||||
|
||||
24
vendor/github.com/dromara/carbon/v2/lang/fi.json
generated
vendored
Normal file
24
vendor/github.com/dromara/carbon/v2/lang/fi.json
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "Finnish",
|
||||
"author": "https://cursor.com/",
|
||||
"months": "Tammikuu|Helmikuu|Maaliskuu|Huhtikuu|Toukokuu|Kesäkuu|Heinäkuu|Elokuu|Syyskuu|Lokakuu|Marraskuu|Joulukuu",
|
||||
"short_months": "Tam|Hel|Maa|Huh|Tou|Kes|Hei|Elo|Syy|Lok|Mar|Jou",
|
||||
"weeks": "Sunnuntai|Maanantai|Tiistai|Keskiviikko|Torstai|Perjantai|Lauantai",
|
||||
"short_weeks": "Su|Ma|Ti|Ke|To|Pe|La",
|
||||
"seasons": "Kevät|Kesä|Syksy|Talvi",
|
||||
"constellations": "Oinas|Härkä|Kaksoset|Rapu|Leijona|Neitsyt|Vaaka|Skorpioni|Jousimies|Kauris|Vesimies|Kalat",
|
||||
"year": "1 vuosi|%d vuotta",
|
||||
"month": "1 kuukausi|%d kuukautta",
|
||||
"week": "1 viikko|%d viikkoa",
|
||||
"day": "1 päivä|%d päivää",
|
||||
"hour": "1 tunti|%d tuntia",
|
||||
"minute": "1 minuutti|%d minuuttia",
|
||||
"second": "1 sekunti|%d sekuntia",
|
||||
"now": "juuri nyt",
|
||||
"ago": "%s sitten",
|
||||
"from_now": "%s päästä",
|
||||
"before": "%s ennen",
|
||||
"after": "%s jälkeen"
|
||||
}
|
||||
|
||||
|
||||
1
vendor/github.com/dromara/carbon/v2/lang/it.json
generated
vendored
1
vendor/github.com/dromara/carbon/v2/lang/it.json
generated
vendored
@@ -6,6 +6,7 @@
|
||||
"weeks": "Domenica|Lunedí|Martedí|Mercoledí|Giovedí|Venerdí|Sabato",
|
||||
"short_weeks": "Dom|Lun|Mar|Mer|Gio|Ven|Sab",
|
||||
"seasons": "Primavera|Estate|Autunno|Inverno",
|
||||
"constellations": "Ariete|Toro|Gemelli|Cancro|Leone|Vergine|Bilancia|Scorpione|Sagittario|Capricorno|Acquario|Pesci",
|
||||
"year": "1 anno|%d anni",
|
||||
"month": "1 mese|%d mesi",
|
||||
"week": "1 settimana|%d settimane",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"months": "일월|이월|삼월|사월|오월|유월|칠월|팔월|구월|시월|십일월|십이월",
|
||||
"short_months": "1월|2월|3월|4월|5월|6월|7월|8월|9월|10월|11월|12월",
|
||||
"weeks": "일요일|월요일|화요일|수요일|목요일|금요일|토요일",
|
||||
"short_weeks": "일요일|월요일|화요일|수요일|목요일|금요일|토요일",
|
||||
"short_weeks": "일|월|화|수|목|금|토",
|
||||
"seasons": "봄|여름|가을|겨울",
|
||||
"constellations": "양자리|황소자리|쌍둥이자리|게자리|사자자리|처녀자리|천칭자리|전갈자리|사수자리|염소자리|물병자리|물고기자리",
|
||||
"year": "%d 년",
|
||||
@@ -15,8 +15,8 @@
|
||||
"minute": "%d 분",
|
||||
"second": "%d 초",
|
||||
"now": "방금",
|
||||
"ago": "%s앞",
|
||||
"from_now": "%s후",
|
||||
"before": "%s전",
|
||||
"after": "%s후"
|
||||
"ago": "%s 전",
|
||||
"from_now": "%s 후",
|
||||
"before": "%s 전",
|
||||
"after": "%s 후"
|
||||
}
|
||||
22
vendor/github.com/dromara/carbon/v2/lang/my.json
generated
vendored
Normal file
22
vendor/github.com/dromara/carbon/v2/lang/my.json
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "Myanmar",
|
||||
"author": "https://cursor.com/",
|
||||
"months": "ဇန်နဝါရီ|ဖေဖော်ဝါရီ|မတ်|ဧပြီ|မေ|ဇွန်|ဇူလိုင်|သြဂုတ်|စက်တင်ဘာ|အောက်တိုဘာ|နိုဝင်ဘာ|ဒီဇင်ဘာ",
|
||||
"short_months": "ဇန်|ဖေ|မတ်|ဧပြီ|မေ|ဇွန်|ဇူ|သြ|စက်|အောက်|နို|ဒီ",
|
||||
"weeks": "တနင်္ဂနွေ|တနင်္လာ|အင်္ဂါ|ဗုဒ္ဓဟူး|ကြာသပတေး|သောကြာ|စနေ",
|
||||
"short_weeks": "တနင်္ဂနွေ|တနင်္လာ|အင်္ဂါ|ဗုဒ္ဓဟူး|ကြာသပတေး|သောကြာ|စနေ",
|
||||
"seasons": "နွေဦး|နွေရာသီ|ဆောင်းဦး|ဆောင်းရာသီ",
|
||||
"constellations": "မိဿ|ပြိဿ|မေထုန်|ကရကဋ်|သိဟ်|ကန်|တူ|ဗြိစ္ဆာ|ဓနု|မကရ|ကြွယ်|မိန်",
|
||||
"year": "%d နှစ်",
|
||||
"month": "%d လ",
|
||||
"week": "%d ပတ်",
|
||||
"day": "%d ရက်",
|
||||
"hour": "%d နာရီ",
|
||||
"minute": "%d မိနစ်",
|
||||
"second": "%d စက္ကန့်",
|
||||
"now": "ယခု",
|
||||
"ago": "%s က",
|
||||
"from_now": "%s ကြာ",
|
||||
"before": "%s မတိုင်မီ",
|
||||
"after": "%s ပြီး"
|
||||
}
|
||||
98
vendor/github.com/dromara/carbon/v2/language.go
generated
vendored
98
vendor/github.com/dromara/carbon/v2/language.go
generated
vendored
@@ -4,7 +4,6 @@ import (
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -13,10 +12,14 @@ import (
|
||||
//go:embed lang
|
||||
var fs embed.FS
|
||||
|
||||
var validResourcesKey = []string{
|
||||
"months", "short_months", "weeks", "short_weeks", "seasons", "constellations",
|
||||
"year", "month", "week", "day", "hour", "minute", "second",
|
||||
"now", "ago", "from_now", "before", "after",
|
||||
// localeCache caches parsed locale resources to avoid repeated file loading and JSON parsing
|
||||
var localeCache sync.Map
|
||||
|
||||
// cachedResources holds the cached resources for each language.
|
||||
type cachedResources struct {
|
||||
once sync.Once
|
||||
resources map[string]string
|
||||
err error
|
||||
}
|
||||
|
||||
// Language defines a Language struct.
|
||||
@@ -54,10 +57,11 @@ func (lang *Language) Copy() *Language {
|
||||
}
|
||||
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
resources := lang.resources
|
||||
lang.rw.RUnlock()
|
||||
|
||||
newLang.resources = make(map[string]string)
|
||||
for k, v := range lang.resources {
|
||||
newLang.resources = make(map[string]string, len(resources))
|
||||
for k, v := range resources {
|
||||
newLang.resources[k] = v
|
||||
}
|
||||
return newLang
|
||||
@@ -73,21 +77,47 @@ func (lang *Language) SetLocale(locale string) *Language {
|
||||
return lang
|
||||
}
|
||||
|
||||
// Early return if locale hasn't changed and resources are already loaded
|
||||
lang.rw.RLock()
|
||||
if lang.locale == locale && lang.resources != nil && len(lang.resources) > 0 {
|
||||
lang.rw.RUnlock()
|
||||
return lang
|
||||
}
|
||||
lang.rw.RUnlock()
|
||||
|
||||
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)
|
||||
load, _ := localeCache.LoadOrStore(fileName, new(cachedResources))
|
||||
entry := load.(*cachedResources)
|
||||
|
||||
entry.once.Do(func() {
|
||||
bs, err := fs.ReadFile(fileName)
|
||||
if err != nil {
|
||||
entry.err = fmt.Errorf("%w: %w", ErrNotExistLocale(fileName), err)
|
||||
return
|
||||
}
|
||||
|
||||
var resources map[string]string
|
||||
_ = json.Unmarshal(bs, &resources)
|
||||
entry.resources = resources
|
||||
})
|
||||
|
||||
if entry.err != nil {
|
||||
lang.Error = entry.err
|
||||
return lang
|
||||
}
|
||||
|
||||
var resources map[string]string
|
||||
_ = json.Unmarshal(bs, &resources)
|
||||
// Create a copy of the cached resources to avoid modifying the cache
|
||||
// Pre-allocate with exact capacity for better memory efficiency
|
||||
newResources := make(map[string]string, len(entry.resources))
|
||||
for k, v := range entry.resources {
|
||||
newResources[k] = v
|
||||
}
|
||||
|
||||
lang.rw.Lock()
|
||||
defer lang.rw.Unlock()
|
||||
|
||||
lang.locale = locale
|
||||
lang.resources = resources
|
||||
lang.resources = newResources
|
||||
lang.rw.Unlock()
|
||||
|
||||
return lang
|
||||
}
|
||||
|
||||
@@ -105,10 +135,6 @@ func (lang *Language) SetResources(resources map[string]string) *Language {
|
||||
defer lang.rw.Unlock()
|
||||
|
||||
for k, v := range resources {
|
||||
if !slices.Contains(validResourcesKey, k) {
|
||||
lang.Error = ErrInvalidResourcesError(resources)
|
||||
return lang
|
||||
}
|
||||
lang.resources[k] = v
|
||||
}
|
||||
return lang
|
||||
@@ -120,25 +146,35 @@ func (lang *Language) translate(unit string, value int64) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
lang.rw.Lock()
|
||||
if len(lang.resources) == 0 {
|
||||
lang.rw.Unlock()
|
||||
lang.SetLocale(DefaultLocale)
|
||||
lang.rw.Lock()
|
||||
}
|
||||
lang.rw.RLock()
|
||||
resources := lang.resources
|
||||
defer lang.rw.Unlock()
|
||||
lang.rw.RUnlock()
|
||||
|
||||
slice := strings.Split(resources[unit], "|")
|
||||
// If resources is empty, set default locale and retry
|
||||
if len(resources) == 0 {
|
||||
lang.SetLocale(DefaultLocale)
|
||||
lang.rw.RLock()
|
||||
resources = lang.resources
|
||||
lang.rw.RUnlock()
|
||||
}
|
||||
if resources == nil || len(resources) == 0 {
|
||||
return ""
|
||||
}
|
||||
resource, exists := resources[unit]
|
||||
if !exists {
|
||||
return ""
|
||||
}
|
||||
slice := strings.Split(resource, "|")
|
||||
number := getAbsValue(value)
|
||||
str := strconv.FormatInt(value, 10)
|
||||
if len(slice) == 1 {
|
||||
return strings.Replace(slice[0], "%d", strconv.FormatInt(value, 10), 1)
|
||||
return strings.Replace(slice[0], "%d", str, 1)
|
||||
}
|
||||
if int64(len(slice)) <= number {
|
||||
return strings.Replace(slice[len(slice)-1], "%d", strconv.FormatInt(value, 10), 1)
|
||||
return strings.Replace(slice[len(slice)-1], "%d", str, 1)
|
||||
}
|
||||
if !strings.Contains(slice[number-1], "%d") && value < 0 {
|
||||
return "-" + slice[number-1]
|
||||
}
|
||||
return strings.Replace(slice[number-1], "%d", strconv.FormatInt(value, 10), 1)
|
||||
return strings.Replace(slice[number-1], "%d", str, 1)
|
||||
}
|
||||
|
||||
44
vendor/github.com/dromara/carbon/v2/outputer.go
generated
vendored
44
vendor/github.com/dromara/carbon/v2/outputer.go
generated
vendored
@@ -35,10 +35,15 @@ func (c *Carbon) ToMonthString(timezone ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
c.lang.rw.RLock()
|
||||
defer c.lang.rw.RUnlock()
|
||||
lang := c.lang
|
||||
if lang == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if resources, ok := c.lang.resources["months"]; ok {
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
if resources, ok := lang.resources["months"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == MonthsPerYear {
|
||||
return slice[c.Month()-1]
|
||||
@@ -56,10 +61,15 @@ func (c *Carbon) ToShortMonthString(timezone ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
c.lang.rw.RLock()
|
||||
defer c.lang.rw.RUnlock()
|
||||
lang := c.lang
|
||||
if lang == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if resources, ok := c.lang.resources["short_months"]; ok {
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
if resources, ok := lang.resources["short_months"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == MonthsPerYear {
|
||||
return slice[c.Month()-1]
|
||||
@@ -77,10 +87,15 @@ func (c *Carbon) ToWeekString(timezone ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
c.lang.rw.RLock()
|
||||
defer c.lang.rw.RUnlock()
|
||||
lang := c.lang
|
||||
if lang == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if resources, ok := c.lang.resources["weeks"]; ok {
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
if resources, ok := lang.resources["weeks"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == DaysPerWeek {
|
||||
return slice[c.DayOfWeek()%DaysPerWeek]
|
||||
@@ -98,10 +113,15 @@ func (c *Carbon) ToShortWeekString(timezone ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
c.lang.rw.RLock()
|
||||
defer c.lang.rw.RUnlock()
|
||||
lang := c.lang
|
||||
if lang == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if resources, ok := c.lang.resources["short_weeks"]; ok {
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
if resources, ok := lang.resources["short_weeks"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == DaysPerWeek {
|
||||
return slice[c.DayOfWeek()%DaysPerWeek]
|
||||
|
||||
106
vendor/github.com/dromara/carbon/v2/parser.go
generated
vendored
106
vendor/github.com/dromara/carbon/v2/parser.go
generated
vendored
@@ -12,20 +12,11 @@ func Parse(value string, timezone ...string) *Carbon {
|
||||
if value == "" {
|
||||
return &Carbon{isEmpty: true}
|
||||
}
|
||||
var (
|
||||
tz string
|
||||
tt StdTime
|
||||
loc *Location
|
||||
err error
|
||||
)
|
||||
if len(timezone) > 0 {
|
||||
tz = timezone[0]
|
||||
} else {
|
||||
tz = DefaultTimezone
|
||||
}
|
||||
if loc, err = parseTimezone(tz); err != nil {
|
||||
loc, err := getLocation(timezone...)
|
||||
if err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
|
||||
switch value {
|
||||
case "now":
|
||||
return Now().SetLocation(loc)
|
||||
@@ -34,9 +25,10 @@ func Parse(value string, timezone ...string) *Carbon {
|
||||
case "tomorrow":
|
||||
return Tomorrow().SetLocation(loc)
|
||||
}
|
||||
|
||||
c := NewCarbon().SetLocation(loc)
|
||||
for _, layout := range defaultLayouts {
|
||||
if tt, err = time.ParseInLocation(layout, value, loc); err == nil {
|
||||
if tt, err := time.ParseInLocation(layout, value, loc); err == nil {
|
||||
c.time = tt
|
||||
c.currentLayout = layout
|
||||
return c
|
||||
@@ -56,22 +48,14 @@ func ParseByLayout(value, layout string, timezone ...string) *Carbon {
|
||||
if layout == "" {
|
||||
return &Carbon{Error: ErrEmptyLayout()}
|
||||
}
|
||||
var (
|
||||
tz string
|
||||
tt StdTime
|
||||
loc *Location
|
||||
err error
|
||||
)
|
||||
if len(timezone) > 0 {
|
||||
tz = timezone[0]
|
||||
} else {
|
||||
tz = DefaultTimezone
|
||||
}
|
||||
if loc, err = parseTimezone(tz); err != nil {
|
||||
|
||||
loc, err := getLocation(timezone...)
|
||||
if err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
|
||||
if tt, err = time.ParseInLocation(layout, value, loc); err != nil {
|
||||
tt, err := time.ParseInLocation(layout, value, loc)
|
||||
if err != nil {
|
||||
return &Carbon{Error: fmt.Errorf("%w: %w", ErrMismatchedLayout(value, layout), err)}
|
||||
}
|
||||
|
||||
@@ -92,10 +76,21 @@ func ParseByFormat(value, format string, timezone ...string) *Carbon {
|
||||
if format == "" {
|
||||
return &Carbon{Error: ErrEmptyFormat()}
|
||||
}
|
||||
c := ParseByLayout(value, format2layout(format), timezone...)
|
||||
if c.HasError() {
|
||||
c.Error = fmt.Errorf("%w: %w", ErrMismatchedFormat(value, format), c.Error)
|
||||
loc, err := getLocation(timezone...)
|
||||
if err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
|
||||
layout := format2layout(format)
|
||||
tt, err := time.ParseInLocation(layout, value, loc)
|
||||
if err != nil {
|
||||
return &Carbon{Error: fmt.Errorf("%w: %w", ErrMismatchedFormat(value, format), err)}
|
||||
}
|
||||
|
||||
c := NewCarbon()
|
||||
c.loc = loc
|
||||
c.time = tt
|
||||
c.currentLayout = layout
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -109,23 +104,15 @@ func ParseByLayouts(value string, layouts []string, timezone ...string) *Carbon
|
||||
if len(layouts) == 0 {
|
||||
return &Carbon{Error: ErrEmptyLayout()}
|
||||
}
|
||||
var (
|
||||
tz string
|
||||
tt StdTime
|
||||
loc *Location
|
||||
err error
|
||||
)
|
||||
if len(timezone) > 0 {
|
||||
tz = timezone[0]
|
||||
} else {
|
||||
tz = DefaultTimezone
|
||||
}
|
||||
if loc, err = parseTimezone(tz); err != nil {
|
||||
|
||||
loc, err := getLocation(timezone...)
|
||||
if err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
|
||||
c := NewCarbon().SetLocation(loc)
|
||||
for _, layout := range layouts {
|
||||
if tt, err = time.ParseInLocation(layout, value, loc); err == nil {
|
||||
if tt, err := time.ParseInLocation(layout, value, loc); err == nil {
|
||||
c.time = tt
|
||||
c.currentLayout = layout
|
||||
return c
|
||||
@@ -145,21 +132,32 @@ func ParseByFormats(value string, formats []string, timezone ...string) *Carbon
|
||||
if len(formats) == 0 {
|
||||
return &Carbon{Error: ErrEmptyFormat()}
|
||||
}
|
||||
var (
|
||||
tz string
|
||||
err error
|
||||
)
|
||||
|
||||
loc, err := getLocation(timezone...)
|
||||
if err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
|
||||
c := NewCarbon().SetLocation(loc)
|
||||
for _, format := range formats {
|
||||
layout := format2layout(format)
|
||||
if tt, err := time.ParseInLocation(layout, value, loc); err == nil {
|
||||
c.time = tt
|
||||
c.currentLayout = layout
|
||||
return c
|
||||
}
|
||||
}
|
||||
c.Error = ErrFailedParse(value)
|
||||
return c
|
||||
}
|
||||
|
||||
// getLocation parses and returns location from timezone parameter with fallback to default.
|
||||
func getLocation(timezone ...string) (*Location, error) {
|
||||
var tz string
|
||||
if len(timezone) > 0 {
|
||||
tz = timezone[0]
|
||||
} else {
|
||||
tz = DefaultTimezone
|
||||
}
|
||||
if _, err = parseTimezone(tz); err != nil {
|
||||
return &Carbon{Error: err}
|
||||
}
|
||||
var layouts []string
|
||||
for _, v := range formats {
|
||||
layouts = append(layouts, format2layout(v))
|
||||
}
|
||||
return ParseByLayouts(value, layouts, tz)
|
||||
return parseTimezone(tz)
|
||||
}
|
||||
|
||||
11
vendor/github.com/dromara/carbon/v2/season.go
generated
vendored
11
vendor/github.com/dromara/carbon/v2/season.go
generated
vendored
@@ -26,10 +26,15 @@ func (c *Carbon) Season() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
c.lang.rw.RLock()
|
||||
defer c.lang.rw.RUnlock()
|
||||
lang := c.lang
|
||||
if lang == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
if resources, ok := c.lang.resources["seasons"]; ok {
|
||||
lang.rw.RLock()
|
||||
defer lang.rw.RUnlock()
|
||||
|
||||
if resources, ok := lang.resources["seasons"]; ok {
|
||||
slice := strings.Split(resources, "|")
|
||||
if len(slice) == QuartersPerYear {
|
||||
return slice[seasons[c.Month()]]
|
||||
|
||||
420
vendor/github.com/dromara/carbon/v2/test_report.cn.md
generated
vendored
420
vendor/github.com/dromara/carbon/v2/test_report.cn.md
generated
vendored
@@ -1,420 +0,0 @@
|
||||
# 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
415
vendor/github.com/dromara/carbon/v2/test_report.en.md
generated
vendored
@@ -1,415 +0,0 @@
|
||||
# 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
414
vendor/github.com/dromara/carbon/v2/test_report.ja.md
generated
vendored
@@ -1,414 +0,0 @@
|
||||
# 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
414
vendor/github.com/dromara/carbon/v2/test_report.ko.md
generated
vendored
@@ -1,414 +0,0 @@
|
||||
# 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 프로젝트는 전체적인 성능이 우수하며, 특히 핵심 기능과 역법 변환 면에서 뛰어난 성능을 보여주며, 고성능이고 기능이 완전한 날짜 시간 처리 라이브러리입니다.
|
||||
85
vendor/github.com/dromara/carbon/v2/traveler.go
generated
vendored
85
vendor/github.com/dromara/carbon/v2/traveler.go
generated
vendored
@@ -58,13 +58,27 @@ func (c *Carbon) AddDuration(duration string) *Carbon {
|
||||
c.Error = err
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(td)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(td)
|
||||
return result
|
||||
}
|
||||
|
||||
// SubDuration subtracts duration.
|
||||
func (c *Carbon) SubDuration(duration string) *Carbon {
|
||||
return c.AddDuration("-" + duration)
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
var (
|
||||
td Duration
|
||||
err error
|
||||
)
|
||||
if td, err = parseDuration(duration); err != nil {
|
||||
c.Error = err
|
||||
return c
|
||||
}
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(-td)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddCenturies adds some centuries.
|
||||
@@ -152,8 +166,9 @@ func (c *Carbon) AddYears(years int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().AddDate(years, 0, 0)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().AddDate(years, 0, 0)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddYearsNoOverflow adds some years without overflowing month.
|
||||
@@ -161,15 +176,16 @@ func (c *Carbon) AddYearsNoOverflow(years int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
nanosecond := c.Nanosecond()
|
||||
year, month, day, hour, minute, second := c.DateTime()
|
||||
result := c.Copy()
|
||||
nanosecond := result.Nanosecond()
|
||||
year, month, day, hour, minute, second := result.DateTime()
|
||||
// get the last day of this month after some years
|
||||
lastYear, lastMonth, lastDay := time.Date(year+years, time.Month(month+1), 0, hour, minute, second, nanosecond, c.loc).Date()
|
||||
if day > lastDay {
|
||||
day = lastDay
|
||||
}
|
||||
c.time = time.Date(lastYear, lastMonth, day, hour, minute, second, nanosecond, c.loc)
|
||||
return c
|
||||
result.time = time.Date(lastYear, lastMonth, day, hour, minute, second, nanosecond, c.loc)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddYear adds one year.
|
||||
@@ -232,7 +248,7 @@ func (c *Carbon) SubQuarters(quarters int) *Carbon {
|
||||
|
||||
// SubQuartersNoOverflow subtracts some quarters without overflowing month.
|
||||
func (c *Carbon) SubQuartersNoOverflow(quarters int) *Carbon {
|
||||
return c.AddMonthsNoOverflow(-quarters * MonthsPerQuarter)
|
||||
return c.AddQuartersNoOverflow(-quarters)
|
||||
}
|
||||
|
||||
// SubQuarter subtracts one quarter.
|
||||
@@ -250,8 +266,9 @@ func (c *Carbon) AddMonths(months int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().AddDate(0, months, 0)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().AddDate(0, months, 0)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddMonthsNoOverflow adds some months without overflowing month.
|
||||
@@ -259,15 +276,16 @@ func (c *Carbon) AddMonthsNoOverflow(months int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
nanosecond := c.Nanosecond()
|
||||
year, month, day, hour, minute, second := c.DateTime()
|
||||
result := c.Copy()
|
||||
nanosecond := result.Nanosecond()
|
||||
year, month, day, hour, minute, second := result.DateTime()
|
||||
// get the last day of this month after some months
|
||||
lastYear, lastMonth, lastDay := time.Date(year, time.Month(month+months+1), 0, hour, minute, second, nanosecond, c.loc).Date()
|
||||
if day > lastDay {
|
||||
day = lastDay
|
||||
}
|
||||
c.time = time.Date(lastYear, lastMonth, day, hour, minute, second, nanosecond, c.loc)
|
||||
return c
|
||||
result.time = time.Date(lastYear, lastMonth, day, hour, minute, second, nanosecond, c.loc)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddMonth adds one month.
|
||||
@@ -325,8 +343,9 @@ func (c *Carbon) AddDays(days int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().AddDate(0, 0, days)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().AddDate(0, 0, days)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddDay adds one day.
|
||||
@@ -349,8 +368,9 @@ func (c *Carbon) AddHours(hours int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(Duration(hours) * time.Hour)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(Duration(hours) * time.Hour)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddHour adds one hour.
|
||||
@@ -373,8 +393,9 @@ func (c *Carbon) AddMinutes(minutes int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(Duration(minutes) * time.Minute)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(Duration(minutes) * time.Minute)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddMinute adds one minute.
|
||||
@@ -397,8 +418,9 @@ func (c *Carbon) AddSeconds(seconds int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(Duration(seconds) * time.Second)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(Duration(seconds) * time.Second)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddSecond adds one second.
|
||||
@@ -421,8 +443,9 @@ func (c *Carbon) AddMilliseconds(milliseconds int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(Duration(milliseconds) * time.Millisecond)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(Duration(milliseconds) * time.Millisecond)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddMillisecond adds one millisecond.
|
||||
@@ -445,8 +468,9 @@ func (c *Carbon) AddMicroseconds(microseconds int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(Duration(microseconds) * time.Microsecond)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(Duration(microseconds) * time.Microsecond)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddMicrosecond adds one microsecond.
|
||||
@@ -469,8 +493,9 @@ func (c *Carbon) AddNanoseconds(nanoseconds int) *Carbon {
|
||||
if c.IsInvalid() {
|
||||
return c
|
||||
}
|
||||
c.time = c.StdTime().Add(Duration(nanoseconds) * time.Nanosecond)
|
||||
return c
|
||||
result := c.Copy()
|
||||
result.time = c.StdTime().Add(Duration(nanoseconds) * time.Nanosecond)
|
||||
return result
|
||||
}
|
||||
|
||||
// AddNanosecond adds one nanosecond.
|
||||
|
||||
1
vendor/github.com/dromara/carbon/v2/type_carbon.go
generated
vendored
1
vendor/github.com/dromara/carbon/v2/type_carbon.go
generated
vendored
@@ -55,6 +55,7 @@ func (c Carbon) MarshalJSON() ([]byte, error) {
|
||||
func (c *Carbon) UnmarshalJSON(src []byte) error {
|
||||
v := string(bytes.Trim(src, `"`))
|
||||
if v == "" || v == "null" {
|
||||
c.isEmpty = true
|
||||
return nil
|
||||
}
|
||||
*c = *ParseByLayout(v, DefaultLayout)
|
||||
|
||||
4
vendor/github.com/dromara/carbon/v2/type_timestamp.go
generated
vendored
4
vendor/github.com/dromara/carbon/v2/type_timestamp.go
generated
vendored
@@ -90,8 +90,8 @@ func (t *TimestampType[T]) UnmarshalJSON(src []byte) error {
|
||||
ts int64
|
||||
err error
|
||||
)
|
||||
if ts, err = parseTimestamp(v); err != nil {
|
||||
return err
|
||||
if ts, err = strconv.ParseInt(v, 10, 64); err != nil {
|
||||
return ErrInvalidTimestamp(v)
|
||||
}
|
||||
var c *Carbon
|
||||
switch t.getPrecision() {
|
||||
|
||||
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -138,8 +138,8 @@ 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.11
|
||||
## explicit; go 1.21
|
||||
# github.com/dromara/carbon/v2 v2.6.14
|
||||
## explicit; go 1.18
|
||||
github.com/dromara/carbon/v2
|
||||
github.com/dromara/carbon/v2/calendar
|
||||
github.com/dromara/carbon/v2/calendar/hebrew
|
||||
|
||||
Reference in New Issue
Block a user