chore: import upstream snapshot with attribution
CI / Check and lint (push) Failing after 1s
Lint / Lint (ubuntu-latest) (push) Failing after 1s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:22:32 +08:00
commit 39dbe3a57d
1131 changed files with 272709 additions and 0 deletions
+210
View File
@@ -0,0 +1,210 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package day
import (
"strings"
"time"
)
var placeholder = map[string]string{
"YY": "06", // 06 year
"YYYY": "2006", // 2006 full year
"M": "1", // 1-12 month
"MM": "01", // 01-12 month
"MMM": "Jan", // Jan-Dec month
"MMMM": "January", // January-December month
"D": "2", // 1-31 date
"DD": "02", // 01-31 date preset 0
"H": "15", // 00-23 hour 24
"HH": "15", // 00-23 hour 24
"h": "3", // 1-12 hour 12
"hh": "03", // 01-12 hour 12
"m": "4", // 0-59 minute
"mm": "04", // 00-59 minute
"s": "5", // 0-59 second
"ss": "05", // 00-59 second
"A": "PM", // AM / PM
"a": "pm", // am / pm
"[at]": "at", // at string
}
func Format(unix int64, format, tz string) (formatted string) {
/*l := len(placeholders) - 1
for i := l; i >= 0; i-- {
format = strings.ReplaceAll(format, placeholders[i].old, placeholders[i].new)
}*/
var toFormat strings.Builder
from := []rune(format)
for len(from) > 0 {
to, suffix := nextStdChunk(from)
toFormat.WriteString(string(to))
from = suffix
}
_, _ = time.LoadLocation(tz)
formatted = time.Unix(unix, 0).Format(toFormat.String())
return
}
func nextStdChunk(from []rune) (to, suffix []rune) {
if len(from) == 0 {
to = []rune{}
suffix = []rune{}
return
}
s := string(from[0])
old := ""
switch s {
case "Y":
if len(from) >= 4 && string(from[:4]) == "YYYY" {
old = "YYYY"
} else if len(from) >= 2 && string(from[:2]) == "YY" {
old = "YY"
}
case "M":
for i := 4; i > 0; i-- {
if len(from) >= i {
switch string(from[:i]) {
case "MMMM":
old = "MMMM"
case "MMM":
old = "MMM"
case "MM":
old = "MM"
case "M":
old = "M"
}
}
if old != "" {
break
}
}
case "D":
for i := 2; i >= 0; i-- {
if len(from) >= i {
switch string(from[:i]) {
case "DD":
old = "DD"
case "D":
old = "D"
}
}
if old != "" {
break
}
}
case "H":
for i := 2; i >= 0; i-- {
if len(from) >= i {
switch string(from[:i]) {
case "HH":
old = "HH"
case "H":
old = "H"
}
}
if old != "" {
break
}
}
case "h":
for i := 2; i >= 0; i-- {
if len(from) >= i {
switch string(from[:i]) {
case "hh":
old = "hh"
case "h":
old = "h"
}
}
if old != "" {
break
}
}
case "m":
for i := 2; i >= 0; i-- {
if len(from) >= i {
switch string(from[:i]) {
case "mm":
old = "mm"
case "m":
old = "m"
}
}
if old != "" {
break
}
}
case "s":
for i := 2; i >= 0; i-- {
if len(from) >= i {
switch string(from[:i]) {
case "ss":
old = "ss"
case "s":
old = "s"
}
}
if old != "" {
break
}
}
case "A":
old = "A"
case "a":
old = "a"
case "[":
// treat anything inside [] as literal text, e.g. [at], [a las], [o]
end := -1
for i := 1; i < len(from); i++ {
if from[i] == ']' {
end = i
break
}
}
if end != -1 {
to = []rune(string(from[1:end]))
suffix = from[end+1:]
return
}
// no closing bracket, fall back to literal "["
old = "["
default:
old = s
}
if old == "" {
// safety: always consume at least one rune
old = s
}
tos, ok := placeholder[old]
if !ok {
to = []rune(old)
} else {
to = []rune(tos)
}
suffix = from[len([]rune(old)):]
return
}
+104
View File
@@ -0,0 +1,104 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package day
import (
"os"
"path/filepath"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestFormat(t *testing.T) {
sec := int64(1700000000)
tz := "UTC"
actual := Format(sec, "MMM D, YYYY [a las] HH:mm", tz)
expected := time.Unix(sec, 0).Format("Jan 2, 2006") + " a las " + time.Unix(sec, 0).Format("15:04")
assert.Equal(t, expected, actual)
}
func TestFormat_AllLanguagesNoHang(t *testing.T) {
_, currentFile, _, ok := runtime.Caller(0)
if !ok {
t.Fatalf("unable to determine test file path")
}
i18nDir := filepath.Clean(filepath.Join(filepath.Dir(currentFile), "..", "..", "i18n"))
entries, err := os.ReadDir(i18nDir)
if err != nil {
t.Fatalf("read i18n dir: %v", err)
}
type datesConfig struct {
LongDate string `yaml:"long_date"`
LongDateWithYear string `yaml:"long_date_with_year"`
LongDateWithTime string `yaml:"long_date_with_time"`
}
type uiConfig struct {
Dates datesConfig `yaml:"dates"`
}
type fileConfig struct {
UI uiConfig `yaml:"ui"`
}
sec := int64(1700000000)
tz := "UTC"
for _, entry := range entries {
name := entry.Name()
if entry.IsDir() || filepath.Ext(name) != ".yaml" || name == "i18n.yaml" {
continue
}
data, err := os.ReadFile(filepath.Join(i18nDir, name))
if err != nil {
t.Fatalf("read %s: %v", name, err)
}
var cfg fileConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
t.Fatalf("parse %s: %v", name, err)
}
formats := []string{
cfg.UI.Dates.LongDate,
cfg.UI.Dates.LongDateWithYear,
cfg.UI.Dates.LongDateWithTime,
}
for _, format := range formats {
if format == "" {
continue
}
done := make(chan struct{})
go func(f string) {
_ = Format(sec, f, tz)
close(done)
}(format)
select {
case <-done:
case <-time.After(200 * time.Millisecond):
t.Fatalf("format hang in %s: %q", name, format)
}
}
}
}