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  }