github.com/richardwilkes/toolbox@v1.121.0/txt/duration.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package txt 11 12 import ( 13 "fmt" 14 "strconv" 15 "strings" 16 "time" 17 18 "github.com/richardwilkes/toolbox/errs" 19 ) 20 21 // ParseDuration parses the duration string, as produced by FormatDuration(). 22 func ParseDuration(duration string) (time.Duration, error) { 23 parts := strings.Split(strings.TrimSpace(duration), ":") 24 if len(parts) != 3 { 25 return 0, errs.New("Invalid format") 26 } 27 hours, err := strconv.Atoi(parts[0]) 28 if err != nil || hours < 0 { 29 return 0, errs.New("Invalid hour format") 30 } 31 minutes, err := strconv.Atoi(parts[1]) 32 if err != nil || minutes < 0 { 33 return 0, errs.New("Invalid minute format") 34 } 35 parts = strings.Split(parts[2], ".") 36 var seconds int 37 var millis int 38 switch len(parts) { 39 case 2: 40 if millis, err = strconv.Atoi(parts[1]); err != nil || millis < 0 { 41 return 0, errs.New("Invalid millisecond format") 42 } 43 fallthrough 44 case 1: 45 if seconds, err = strconv.Atoi(parts[0]); err != nil || seconds < 0 { 46 return 0, errs.New("Invalid second format") 47 } 48 default: 49 return 0, errs.New("Invalid second format: too many decimal points") 50 } 51 return time.Duration(hours)*time.Hour + time.Duration(minutes)*time.Minute + time.Duration(seconds)*time.Second + time.Duration(millis)*time.Millisecond, nil 52 } 53 54 // FormatDuration formats the duration as either "0:00:00" or "0:00:00.000". 55 func FormatDuration(duration time.Duration, includeMillis bool) string { 56 if duration < 0 { 57 duration = 0 58 } 59 hours := duration / time.Hour 60 duration -= hours * time.Hour 61 minutes := duration / time.Minute 62 duration -= minutes * time.Minute 63 seconds := duration / time.Second 64 duration -= seconds * time.Second 65 if includeMillis { 66 return fmt.Sprintf("%d:%02d:%02d.%03d", hours, minutes, seconds, duration/time.Millisecond) 67 } 68 return fmt.Sprintf("%d:%02d:%02d", hours, minutes, seconds) 69 } 70 71 // DurationToCode turns a time.Duration into more human-readable text required for code than a simple number of 72 // nanoseconds. 73 func DurationToCode(duration time.Duration) string { 74 var buffer strings.Builder 75 if duration >= time.Hour { 76 fmt.Fprintf(&buffer, "%d * time.Hour", duration/time.Hour) 77 duration -= (duration / time.Hour) * time.Hour 78 } 79 if duration >= time.Minute { 80 if buffer.Len() > 0 { 81 buffer.WriteString(" + ") 82 } 83 fmt.Fprintf(&buffer, "%d * time.Minute", duration/time.Minute) 84 duration -= (duration / time.Minute) * time.Minute 85 } 86 if duration >= time.Second { 87 if buffer.Len() > 0 { 88 buffer.WriteString(" + ") 89 } 90 fmt.Fprintf(&buffer, "%d * time.Second", duration/time.Second) 91 duration -= (duration / time.Second) * time.Second 92 } 93 if duration >= time.Millisecond { 94 if buffer.Len() > 0 { 95 buffer.WriteString(" + ") 96 } 97 fmt.Fprintf(&buffer, "%d * time.Millisecond", duration/time.Millisecond) 98 duration -= (duration / time.Millisecond) * time.Millisecond 99 } 100 if duration >= time.Microsecond { 101 if buffer.Len() > 0 { 102 buffer.WriteString(" + ") 103 } 104 fmt.Fprintf(&buffer, "%d * time.Microsecond", duration/time.Microsecond) 105 duration -= (duration / time.Microsecond) * time.Microsecond 106 } 107 if duration != 0 { 108 if buffer.Len() > 0 { 109 buffer.WriteString(" + ") 110 } 111 fmt.Fprintf(&buffer, "%d", duration) 112 } 113 return buffer.String() 114 }