Skip to content

Commit

Permalink
Add era and zodiac sub-packages
Browse files Browse the repository at this point in the history
  • Loading branch information
spiegel-im-spiegel committed Apr 9, 2022
1 parent 98592e4 commit 898959d
Show file tree
Hide file tree
Showing 9 changed files with 787 additions and 2 deletions.
172 changes: 171 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
)
```

## Usage
## 簡単な使い方

```go
start, _ := koyomi.DateFrom("2019-05-01")
Expand Down Expand Up @@ -53,6 +53,176 @@ io.Copy(os.Stdout, bytes.NewReader(csv))
//"2019-05-21","小満"
```

## おまけ機能

### 西暦⇔和暦 変換

元号を含む和暦と西暦との変換を行います。
元号は以下のものに対応しています。

| 元号 | 起点 |
| ---------------- | -------------- |
| 明治(改暦以降) | 1873年1月1日 |
| 大正 | 1912年7月30日 |
| 昭和 | 1926年12月25日 |
| 平成 | 1989年1月8日 |
| 令和 | 2019年5月1日 |

#### 西暦から和暦への変換

```go
//go:build run
// +build run

package main

import (
"flag"
"fmt"
"os"
"strconv"
"time"

"github.com/goark/koyomi/era"
)

func main() {
flag.Parse()
argsStr := flag.Args()
tm := time.Now()
if len(argsStr) > 0 {
if len(argsStr) < 3 {
fmt.Fprintln(os.Stderr, "年月日を指定してください")
return
}
args := make([]int, 3)
for i := 0; i < 3; i++ {
num, err := strconv.Atoi(argsStr[i])
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
args[i] = num
}
tm = time.Date(args[0], time.Month(args[1]), args[2], 0, 0, 0, 0, time.Local)
}
te := era.New(tm)
n, y := te.YearEraString()
if len(n) == 0 {
fmt.Fprintln(os.Stderr, "正しい年月日を指定してください")
return
}
fmt.Printf("%s%s%d%d\n", n, y, te.Month(), te.Day())
}
```

これを実行すると以下のような結果になります。

```
$ go run era/sample1/sample1.go 2019 4 30
平成31年4月30日
$ go run era/sample1/sample1.go 2019 5 1
令和元年5月1日
```

#### 和暦から西暦への変換

```go
//go:build run
// +build run

package main

import (
"flag"
"fmt"
"os"
"strconv"
"time"

"github.com/goark/koyomi/era"
)

func main() {
flag.Parse()
argsStr := flag.Args()

if len(argsStr) < 4 {
fmt.Fprintln(os.Stderr, "元号 年 月 日 を指定してください")
return
}
name := argsStr[0]
args := make([]int, 3)
for i := 0; i < 3; i++ {
num, err := strconv.Atoi(argsStr[i+1])
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
args[i] = num
}
te := era.Date(era.Name(name), args[0], time.Month(args[1]), args[2], 0, 0, 0, 0, time.Local)
fmt.Println(te.Format("西暦2006年1月2日"))
}
```

これを実行すると以下のような結果になります。

```
$ go run sample2/sample2.go 平成 31 4 30
西暦2019年4月30日
$ go run sample2/sample2.go 令和 1 5 1
西暦2019年5月1日
```

### 十干十二支を数え上げる

```go
//go:build run
// +build run

package main

import (
"flag"
"fmt"
"os"
"time"

"github.com/goark/koyomi/zodiac"
)

func main() {
flag.Parse()
args := flag.Args()
if len(args) < 1 {
fmt.Fprintln(os.Stderr, os.ErrInvalid)
return
}
for _, s := range args {
t, err := time.Parse("2006-01-02", s)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
}
kan, shi := zodiac.ZodiacYearNumber(t.Year())
fmt.Printf("Year %v is %v%v\n", t.Year(), kan, shi)
kan, shi = zodiac.ZodiacDayNumber(t)
fmt.Printf("Day %v is %v%v\n", t.Format("2006-01-02"), kan, shi)
}
}
```

これを実行すると以下のような結果になります。

```
$ go run zodiac/sample/sample.go 2021-07-28
Year 2021 is 辛丑
Day 2021-07-28 is 丁丑
```

## Modules Requirement Graph

[![dependency.png](./dependency.png)](./dependency.png)
Expand Down
2 changes: 1 addition & 1 deletion Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ tasks:
cmds:
- go mod verify
- go test -shuffle on ./...
- docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.45.0 golangci-lint run --enable gosec --timeout 3m0s ./...
- docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint:v1.45.2 golangci-lint run --enable gosec --timeout 3m0s ./...
sources:
- ./go.mod
- '**/*.go'
Expand Down
131 changes: 131 additions & 0 deletions era/era.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package era

import (
"fmt"
"time"
)

//era.eraName は元号名を表す型です。
type eraName int

const (
Unknown eraName = iota //不明な元号
Meiji //明治
Taisho //大正
Showa //昭和
Heisei //平成
Reiwa //令和
)

var eraString = map[eraName]string{
Unknown: "",
Meiji: "明治",
Taisho: "大正",
Showa: "昭和",
Heisei: "平成",
Reiwa: "令和",
}

//era.Name() 関数は元号の文字列から元号名 era.eraName を取得します。
//該当する元号名がない場合は era.Unknown を返します。
func Name(s string) eraName {
for k, v := range eraString {
if v == s {
return k
}
}
return Unknown
}

func (e eraName) String() string {
if s, ok := eraString[e]; ok {
return s
}
return ""
}

//err.Time は元号操作を含む時間クラスです。
type Time struct {
time.Time
}

var (
locJST = time.FixedZone("JST", 9*60*60) //日本標準時
eraTrigger = map[eraName]time.Time{ //各元号の起点
Meiji: time.Date(1873, time.January, 1, 0, 0, 0, 0, locJST), //明治(の改暦) : 1873-01-01
Taisho: time.Date(1912, time.July, 30, 0, 0, 0, 0, locJST), //大正 : 1912-07-30
Showa: time.Date(1926, time.December, 25, 0, 0, 0, 0, locJST), //昭和 : 1926-12-25
Heisei: time.Date(1989, time.January, 8, 0, 0, 0, 0, locJST), //平成 : 1989-01-08
Reiwa: time.Date(2019, time.May, 1, 0, 0, 0, 0, locJST), //令和 : 2019-05-01
}
eraSorted = []eraName{Reiwa, Heisei, Showa, Taisho, Meiji} //ソートされた元号の配列(降順)
)

//era.New() 関数は era.Time インスタンスを生成します。
func New(t time.Time) Time {
return Time{t.In(locJST)} //日本標準時で揃える
}

//era.Date() 関数は 元号・年・月・日・時・分・秒・タイムゾーン を指定して era.Time 型のインスタンスを返します。
//起点が定義されない元号を指定した場合は西暦として処理します。
func Date(en eraName, year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Time {
ofset := 0
if dt, ok := eraTrigger[en]; ok {
ofset = dt.Year() - 1
}
return New(time.Date(year+ofset, month, day, hour, min, sec, nsec, loc))
}

//era.Time.Era() メソッドは元号名 era.eraName のインスタンスを返します。
//元号が不明の場合は era.Unknown を返します。
func (t Time) Era() eraName {
for _, es := range eraSorted {
if !t.Before(eraTrigger[es]) {
return es
}
}
return Unknown

}

//era.Time.YearEra() メソッドは元号付きの年の値を返します。
//元号が不明の場合は (era.Unknown, 0) を返します。
func (t Time) YearEra() (eraName, int) {
era := t.Era()
if era == Unknown {
return Unknown, 0
}
year := t.Year() - eraTrigger[era].Year() + 1
if era == Meiji { //明治のみ5年のオフセットを加算する
return era, year + 5
}
return era, year
}

//era.Time.YearEraString() メソッドは元号付きの年の値を文字列で返します。
//元号が不明の場合は空文字列を返します。
func (t Time) YearEraString() (string, string) {
era, year := t.YearEra()
if era == Unknown || year < 1 {
return "", ""
}
if year == 1 {
return era.String(), "元年"
}
return era.String(), fmt.Sprintf("%d年", year)
}

/* Copyright 2019-2022 Spiegel
*
* Licensed 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.
*/
Loading

0 comments on commit 898959d

Please sign in to comment.