output ics

This commit is contained in:
Muhan Li 2022-03-06 01:48:31 +08:00
parent fcd17029e6
commit 9ad691b033
11 changed files with 178 additions and 48 deletions

2
go.mod
View File

@ -1,3 +1,5 @@
module main
go 1.17
require github.com/google/uuid v1.3.0

2
go.sum Normal file
View 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=

View File

@ -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) }

View File

@ -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)
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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
}

View 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)
}

View File

@ -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
}

View File

@ -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)
}
})
}
}

View File

@ -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)
}