| | | @@ 変更前 2行目〜 / 変更後 2行目〜 @@ |
| 2 | 2 | | |
| 3 | 3 | | import "time" |
| 4 | 4 | | |
| 5 | | − | // v1: よくある書き方(time.Parse で読み、年・月・日をそれぞれ引き、日がマイナスなら前の月の日数を借りる)。 |
| 5 | + | // v2: 入社日に k か月を足し(行き先の月に同じ日がなければ末日にする)、基準日を超えない最大の k を数える。 |
| 6 | + | // time.AddDate は 1月31日 + 1か月 を 3月3日に繰り越すので使わず、末日にそろえる処理を書く。 |
| 7 | + | // 存在しない日付は time.Parse がエラーにするので invalid_date として返す。 |
| 8 | + | func addMonths(t time.Time, k int) time.Time { |
| 9 | + | idx := t.Year()*12 + int(t.Month()) - 1 + k |
| 10 | + | y, m := idx/12, time.Month(idx%12+1) |
| 11 | + | last := time.Date(y, m+1, 0, 0, 0, 0, 0, time.UTC).Day() |
| 12 | + | return time.Date(y, m, min(t.Day(), last), 0, 0, 0, 0, time.UTC) |
| 13 | + | } |
| 14 | + | |
| 15 | + | func daysBetween(a, b time.Time) int { return int(b.Sub(a).Hours()) / 24 } // どちらも UTC の 0:00 なので割り切れる |
| 6 | 16 | | |
| 7 | 17 | | // CalcService は勤続年数を求める。 |
| 8 | 18 | | func CalcService(join, base string) (map[string]any, error) { |
| 9 | | − | j, err := time.Parse("2006-01-02", join) |
| 10 | | − | if err != nil { |
| 11 | | − | return nil, err |
| 12 | | − | } |
| 13 | | − | b, err := time.Parse("2006-01-02", base) |
| 14 | | − | if err != nil { |
| 15 | | − | return nil, err |
| 19 | + | j, err1 := time.Parse("2006-01-02", join) |
| 20 | + | b, err2 := time.Parse("2006-01-02", base) |
| 21 | + | if err1 != nil || err2 != nil { |
| 22 | + | return map[string]any{"error": "invalid_date"}, nil |
| 16 | 23 | | } |
| 17 | 24 | | if b.Before(j) { |
| 18 | 25 | | return map[string]any{"error": "base_before_join"}, nil |
| 19 | 26 | | } |
| 20 | | − | years := b.Year() - j.Year() |
| 21 | | − | months := int(b.Month()) - int(j.Month()) |
| 22 | | − | days := b.Day() - j.Day() |
| 23 | | − | if days < 0 { |
| 24 | | − | months-- |
| 25 | | − | days += time.Date(b.Year(), b.Month(), 0, 0, 0, 0, 0, time.UTC).Day() // 前の月の日数を借りる |
| 27 | + | k := (b.Year()-j.Year())*12 + int(b.Month()) - int(j.Month()) |
| 28 | + | for k > 0 && addMonths(j, k).After(b) { |
| 29 | + | k-- |
| 26 | 30 | | } |
| 27 | | − | if months < 0 { |
| 28 | | − | years-- |
| 29 | | − | months += 12 |
| 30 | | − | } |
| 31 | | − | totalDays := int(b.Sub(j).Hours() / 24) |
| 32 | | − | return map[string]any{"years": years, "months": months, "days": days, "total_months": years*12 + months, "total_days": totalDays}, nil |
| 31 | + | return map[string]any{"years": k / 12, "months": k % 12, "days": daysBetween(addMonths(j, k), b), |
| 32 | + | "total_months": k, "total_days": daysBetween(j, b)}, nil |
| 33 | 33 | | } |