mirror of
https://github.com/muhac/chinese-holidays-calendar.git
synced 2024-11-27 01:50:00 +08:00
output ics
This commit is contained in:
parent
fcd17029e6
commit
9ad691b033
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
@ -7,10 +7,11 @@ type Holidays []Holiday
|
||||
|
||||
// Holiday data per day
|
||||
type Holiday struct {
|
||||
Date time.Time
|
||||
Name string
|
||||
Type int
|
||||
Nth int
|
||||
Group string
|
||||
Date time.Time
|
||||
Name string
|
||||
Type int
|
||||
Nth int
|
||||
}
|
||||
|
||||
func (h Holidays) Len() int { return len(h) }
|
||||
|
@ -1,6 +1,7 @@
|
||||
package input
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"main/parse/base"
|
||||
"main/parse/data"
|
||||
"strings"
|
||||
@ -10,7 +11,7 @@ func NewParser() data.Parser {
|
||||
return parser{}
|
||||
}
|
||||
|
||||
type parser struct {}
|
||||
type parser struct{}
|
||||
|
||||
func (p parser) Parse(raw data.Input) (result base.Holidays) {
|
||||
for _, year := range raw {
|
||||
@ -21,29 +22,27 @@ func (p parser) Parse(raw data.Input) (result base.Holidays) {
|
||||
}
|
||||
|
||||
func parse(raw data.InputRaw) (result base.Holidays, err error) {
|
||||
for _, holiday := range strings.Split(raw.Data, "\n") {
|
||||
if holiday[:2] == "//" {
|
||||
continue
|
||||
}
|
||||
|
||||
for group, holiday := range raw.Data {
|
||||
info := strings.Split(holiday, ";")
|
||||
|
||||
for i, day := range holidays(raw.Year, info[1]) {
|
||||
restDay := base.Holiday{
|
||||
Name: info[0],
|
||||
Nth: i + 1,
|
||||
Date: date(raw.Year, day),
|
||||
Type: base.Rest,
|
||||
Group: fmt.Sprintf("%04d%02d", raw.Year, group),
|
||||
Name: info[0],
|
||||
Nth: i + 1,
|
||||
Date: date(raw.Year, day),
|
||||
Type: base.Rest,
|
||||
}
|
||||
result = append(result, restDay)
|
||||
}
|
||||
|
||||
for i, day := range holidays(raw.Year, info[2]) {
|
||||
workDay := base.Holiday{
|
||||
Name: info[0],
|
||||
Nth: i + 1,
|
||||
Date: date(raw.Year, day),
|
||||
Type: base.Work,
|
||||
Group: fmt.Sprintf("%04d%02d", raw.Year, group),
|
||||
Name: info[0],
|
||||
Nth: i + 1,
|
||||
Date: date(raw.Year, day),
|
||||
Type: base.Work,
|
||||
}
|
||||
result = append(result, workDay)
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ func holidays(year int, daysRaw string) (result []string) {
|
||||
for _, day := range days {
|
||||
if strings.Contains(day, "-") {
|
||||
period := strings.Split(day, "-")
|
||||
for d := date(year, period[0]); d.Before(date(year, period[1]).Add(time.Hour)); d = d.AddDate(0, 0, 1) {
|
||||
for d := date(year, period[0]); !d.After(date(year, period[1])); d = d.AddDate(0, 0, 1) {
|
||||
result = append(result, d.Format("1.2"))
|
||||
}
|
||||
} else {
|
||||
|
@ -1,11 +1,21 @@
|
||||
package data
|
||||
|
||||
import "main/parse/base"
|
||||
import (
|
||||
"main/parse/base"
|
||||
)
|
||||
|
||||
type Reader interface {
|
||||
Read() Input
|
||||
}
|
||||
|
||||
type Parser interface {
|
||||
Parse(Input) base.Holidays
|
||||
}
|
||||
|
||||
type Formatter interface {
|
||||
Format(base.Holidays) Output
|
||||
}
|
||||
|
||||
type Writer interface {
|
||||
Write(Output)
|
||||
}
|
||||
@ -16,15 +26,11 @@ type Input []InputRaw
|
||||
// InputRaw per year
|
||||
type InputRaw struct {
|
||||
Year int
|
||||
Data string
|
||||
Data []string
|
||||
}
|
||||
|
||||
type Output string
|
||||
|
||||
type Parser interface {
|
||||
Parse(Input) base.Holidays
|
||||
}
|
||||
|
||||
type Formatter interface {
|
||||
Format(base.Holidays) Output
|
||||
type Output struct {
|
||||
Prefix string
|
||||
Body []string
|
||||
Suffix string
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"main/parse/base"
|
||||
"main/parse/data"
|
||||
)
|
||||
@ -10,8 +10,23 @@ func NewFormatter(format string) data.Formatter {
|
||||
return formatter{}
|
||||
}
|
||||
|
||||
type formatter struct{}
|
||||
|
||||
func (f formatter) Format(info base.Holidays) data.Output {
|
||||
return data.Output(fmt.Sprintf("%+v", info))
|
||||
type formatter struct {
|
||||
result string
|
||||
}
|
||||
|
||||
func (f formatter) Format(info base.Holidays) (result data.Output) {
|
||||
result.Prefix = IcsHead
|
||||
result.Suffix = IcsTail
|
||||
|
||||
for _, day := range info {
|
||||
outputDay := event{
|
||||
Id: uuid.NewString(),
|
||||
Group: day.Group,
|
||||
Title: getTitle(day),
|
||||
Date: day.Date,
|
||||
Desc: getDesc(day),
|
||||
}
|
||||
result.Body = append(result.Body, outputDay.Ics())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
48
parse/data/output/utils.go
Normal file
48
parse/data/output/utils.go
Normal file
@ -0,0 +1,48 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"main/parse/base"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
IcsHead = "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:-//Rank Technology//Chinese Holidays//EN"
|
||||
IcsEvent = "BEGIN:VEVENT\nDTSTART:%s\nDTEND:%s\nSUMMARY:%s\nDESCRIPTION:%s\nEND:VEVENT"
|
||||
IcsTail = "END:VCALENDAR"
|
||||
)
|
||||
|
||||
// event data
|
||||
type event struct {
|
||||
Id string
|
||||
Group string
|
||||
Title string
|
||||
Date time.Time
|
||||
Desc string
|
||||
}
|
||||
|
||||
func (d event) Ics() string {
|
||||
return fmt.Sprintf(
|
||||
IcsEvent,
|
||||
d.Date.Format("20060102T150405"),
|
||||
d.Date.Add(time.Hour*24).Format("20060102T150405"),
|
||||
d.Title,
|
||||
d.Desc,
|
||||
)
|
||||
}
|
||||
|
||||
func getTitle(item base.Holiday) string {
|
||||
status := map[int]string{
|
||||
base.Rest: "假期",
|
||||
base.Work: "补班",
|
||||
}
|
||||
return fmt.Sprintf("%s %s第%d天", item.Name, status[item.Type], item.Nth)
|
||||
}
|
||||
|
||||
func getDesc(item base.Holiday) string {
|
||||
status := map[int]string{
|
||||
base.Rest: "假期",
|
||||
base.Work: "补班",
|
||||
}
|
||||
return fmt.Sprintf("%s第%d天", status[item.Type], item.Nth)
|
||||
}
|
@ -7,6 +7,7 @@ import (
|
||||
"main/parse/data"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
@ -37,7 +38,17 @@ func (dw dataReader) Read() (result data.Input) {
|
||||
fmt.Printf("Error loading %s: %s", file.Name, err)
|
||||
return
|
||||
}
|
||||
resultChan <- data.InputRaw{Year: file.Year, Data: raw}
|
||||
|
||||
result := data.InputRaw{
|
||||
Year: file.Year,
|
||||
Data: lines(raw),
|
||||
}
|
||||
if len(result.Data) == 0 {
|
||||
fmt.Printf("No data in %s", file.Name)
|
||||
return
|
||||
}
|
||||
|
||||
resultChan <- result
|
||||
}(f)
|
||||
}
|
||||
|
||||
@ -46,8 +57,8 @@ func (dw dataReader) Read() (result data.Input) {
|
||||
close(resultChan)
|
||||
}()
|
||||
|
||||
for data := range resultChan {
|
||||
result = append(result, data)
|
||||
for content := range resultChan {
|
||||
result = append(result, content)
|
||||
}
|
||||
return result
|
||||
}
|
||||
@ -67,11 +78,11 @@ func (dw dataReader) fileList() (result []fileInfo) {
|
||||
}
|
||||
|
||||
func (dw dataReader) load(filename string) (result string, err error) {
|
||||
data, err := ioutil.ReadFile(dw.Dir + filename)
|
||||
content, err := ioutil.ReadFile(dw.Dir + filename)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
return string(data), nil
|
||||
return string(content), nil
|
||||
}
|
||||
|
||||
func year(filename string) (result int, err error) {
|
||||
@ -81,3 +92,22 @@ func year(filename string) (result int, err error) {
|
||||
}
|
||||
return strconv.Atoi(filename[:4])
|
||||
}
|
||||
|
||||
func lines(data string) (result []string) {
|
||||
var (
|
||||
dateSingle = `(\d?\d.\d?\d)`
|
||||
dateRange = fmt.Sprintf(`(%s-%s)`, dateSingle, dateSingle)
|
||||
dateFormat = fmt.Sprintf(`(%s|%s)`, dateSingle, dateRange)
|
||||
dateInputs = fmt.Sprintf(`(%s,)*%s`, dateFormat, dateFormat)
|
||||
dateAccept = fmt.Sprintf(`(|%s)`, dateInputs)
|
||||
dateRegex = regexp.MustCompile(fmt.Sprintf(`^.+;%s;%s$`, dateAccept, dateAccept))
|
||||
)
|
||||
|
||||
for _, line := range strings.Split(data, "\n") {
|
||||
line = strings.TrimSpace(line)
|
||||
if dateRegex.MatchString(line) {
|
||||
result = append(result, line)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package read
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@ -34,3 +35,23 @@ func Test_year(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_lines(t *testing.T) {
|
||||
type args struct {
|
||||
data string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
wantResult []string
|
||||
}{
|
||||
{"1", args{"// none"}, nil},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if gotResult := lines(tt.args.data); !reflect.DeepEqual(gotResult, tt.wantResult) {
|
||||
t.Errorf("lines() = %v, want %v", gotResult, tt.wantResult)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"log"
|
||||
"main/parse/data"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func NewWriter(filename string) data.Writer {
|
||||
@ -16,20 +17,25 @@ type dataWriter struct {
|
||||
}
|
||||
|
||||
func (dw dataWriter) Write(data data.Output) {
|
||||
output := strings.Join(
|
||||
[]string{
|
||||
data.Prefix,
|
||||
strings.Join(data.Body, "\n\n"),
|
||||
data.Suffix,
|
||||
},
|
||||
"\n\n\n",
|
||||
)
|
||||
|
||||
f, err := os.Create(dw.File)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer func() { _ = f.Close() }()
|
||||
|
||||
n, err := f.WriteString(output)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
n, err := f.WriteString(string(data))
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println(dw.File, n, "done")
|
||||
fmt.Println("write", n, "bytes to", dw.File)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user