package datetime import ( "context" "fmt" "strings" "time" "git.yeij.top/AskaEth/Cyrene-Plugins/sdk" ) type DatetimePlugin struct{ sdk.BasePlugin } func (p *DatetimePlugin) Metadata() sdk.PluginMetadata { return sdk.PluginMetadata{ Name: "datetime", DisplayName: "Date & Time", Version: "1.0.0", Description: "Date/time utilities: now, format, arithmetic, diff, timezone list", Category: "utility", Author: sdk.PluginAuthor{Name: "Cyrene Team"}, } } func (p *DatetimePlugin) Tools() []sdk.Tool { return []sdk.Tool{&DatetimeTool{}} } type DatetimeTool struct{ sdk.BaseTool } func (t *DatetimeTool) Definition() sdk.ToolDefinition { return sdk.ToolDefinition{ ID: "datetime", Name: "datetime", DisplayName: "Date & Time", Description: "Date/time utility. Get current time, format dates, date arithmetic, date diff, list timezones.", Category: "utility", Complexity: sdk.ComplexitySimple, Parameters: map[string]interface{}{ "type": "object", "properties": map[string]interface{}{ "action": map[string]interface{}{"type": "string", "enum": []string{"now", "format", "add", "diff", "timezone_list"}}, "format": map[string]interface{}{"type": "string"}, "timezone": map[string]interface{}{"type": "string"}, "date": map[string]interface{}{"type": "string"}, "duration": map[string]interface{}{"type": "string"}, "date2": map[string]interface{}{"type": "string"}, }, "required": []string{"action"}, }, } } func (t *DatetimeTool) Validate(args map[string]interface{}) error { if _, ok := args["action"]; !ok { return fmt.Errorf("missing required parameter: action") } return nil } func (t *DatetimeTool) Execute(_ context.Context, args map[string]interface{}) (*sdk.ToolResult, error) { action, _ := args["action"].(string) tzStr, _ := args["timezone"].(string) loc, _ := parseLocation(tzStr) now := time.Now().In(loc) switch action { case "now": return &sdk.ToolResult{ToolName: "datetime", Success: true, Output: fmt.Sprintf("Current time: %s (unix: %d, zone: %s)", now.Format(time.RFC3339), now.Unix(), loc.String())}, nil case "format": dateStr, _ := args["date"].(string) format, _ := args["format"].(string) if format == "" { format = time.RFC3339 } parsed, err := parseDate(dateStr, loc) if err != nil { return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil } return &sdk.ToolResult{ToolName: "datetime", Success: true, Output: fmt.Sprintf("Formatted: %s", parsed.Format(format))}, nil case "add": dateStr, _ := args["date"].(string) durStr, _ := args["duration"].(string) base := now if dateStr != "" { var err error base, err = parseDate(dateStr, loc) if err != nil { return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil } } result, err := addDuration(base, durStr) if err != nil { return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil } return &sdk.ToolResult{ToolName: "datetime", Success: true, Output: fmt.Sprintf("%s + %s = %s", base.Format(time.RFC3339), durStr, result.Format(time.RFC3339))}, nil case "diff": d1, _ := args["date"].(string) d2, _ := args["date2"].(string) t1, err := parseDate(d1, loc) if err != nil { return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil } t2, err := parseDate(d2, loc) if err != nil { return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: err.Error()}, nil } diff := t2.Sub(t1) if diff < 0 { diff = -diff } days := int(diff.Hours()) / 24 hours := int(diff.Hours()) % 24 minutes := int(diff.Minutes()) % 60 seconds := int(diff.Seconds()) % 60 return &sdk.ToolResult{ToolName: "datetime", Success: true, Output: fmt.Sprintf("Difference: %d days, %d hours, %d minutes, %d seconds", days, hours, minutes, seconds)}, nil case "timezone_list": return &sdk.ToolResult{ToolName: "datetime", Success: true, Output: "Common timezones: UTC, Asia/Shanghai, Asia/Tokyo, Asia/Seoul, Asia/Singapore, Asia/Kolkata, Asia/Dubai, Europe/London, Europe/Paris, Europe/Moscow, America/New_York, America/Chicago, America/Los_Angeles, America/Sao_Paulo, Australia/Sydney, Pacific/Auckland, Africa/Cairo, Africa/Lagos"}, nil default: return &sdk.ToolResult{ToolName: "datetime", Success: false, Error: fmt.Sprintf("unknown action: %s", action)}, nil } } func parseLocation(tz string) (*time.Location, error) { if tz == "" { loc, err := time.LoadLocation("Asia/Shanghai") if err != nil { return time.UTC, nil } return loc, nil } return time.LoadLocation(tz) } func parseDate(s string, loc *time.Location) (time.Time, error) { formats := []string{time.RFC3339, "2006-01-02T15:04:05", "2006-01-02 15:04:05", "2006-01-02", "2006/01/02"} for _, f := range formats { if t, err := time.ParseInLocation(f, s, loc); err == nil { return t, nil } } return time.Time{}, fmt.Errorf("cannot parse date: %s", s) } func addDuration(t time.Time, durStr string) (time.Time, error) { durStr = strings.TrimSpace(durStr) if durStr == "" { return t, nil } // Handle months and years if strings.Contains(durStr, "M") || strings.Contains(durStr, "y") { months := 0 years := 0 if strings.Contains(durStr, "y") { fmt.Sscanf(durStr, "%dy", &years) } if strings.Contains(durStr, "M") { fmt.Sscanf(durStr, "%dM", &months) } return t.AddDate(years, months, 0), nil } d, err := time.ParseDuration(durStr) if err != nil { return t, fmt.Errorf("invalid duration: %s", durStr) } return t.Add(d), nil }