159 lines
6.4 KiB
Plaintext
159 lines
6.4 KiB
Plaintext
// lib_num_to_formatted_str.ks provides several functions for changing numbers (scalers) into strings with specified formats
|
|
// Copyright © 2019,2020,2021,2023 KSLib team
|
|
// Lic. MIT
|
|
|
|
@LAZYGLOBAL OFF.
|
|
@CLOBBERBUILTINS OFF.
|
|
|
|
LOCAL FUNCTION time_converter {
|
|
PARAMETER timeValue, // the time in seconds to convert
|
|
places. // how many time places (e.g HH:MM:SS has 3 places)
|
|
SET timeValue TO TIMESPAN(timeValue).
|
|
|
|
IF timeValue:MINUTES < 1 OR places = 1 {
|
|
RETURN LIST(ROUND(timeValue:SECONDS,2)).
|
|
|
|
} ELSE IF timeValue:HOURS < 1 OR places = 2 {
|
|
RETURN LIST(ROUND(MOD(timeValue:SECONDS,60),2), timeValue:MINUTES).
|
|
|
|
} ELSE IF timeValue:DAYS < 1 OR places = 3 {
|
|
RETURN LIST(ROUND(MOD(timeValue:SECONDS,60),2), timeValue:MINUTE, timeValue:HOURS).
|
|
|
|
} ELSE IF timeValue:YEARS < 1 OR places = 4 {
|
|
RETURN LIST(ROUND(MOD(timeValue:SECONDS,60),2), timeValue:MINUTE, timeValue:HOUR, timeValue:DAYS).
|
|
|
|
} ELSE {
|
|
RETURN LIST(ROUND(MOD(timeValue:SECONDS,60),2), timeValue:MINUTE, timeValue:HOUR, timeValue:DAY, timeValue:YEARS).
|
|
}
|
|
}
|
|
|
|
//adding list of format types
|
|
//formats should be a list of two items
|
|
// the first item is the fixed number of places to show ie a 2 will always show 2 places be it MM:SS or HH:MM or DDD:HH
|
|
// the second item is a list of strings to include after the neumeric value of the place ie "s" to show after the number or seconds
|
|
// the order is seconds, minutes, hours, days, years
|
|
// it must also be at least as long as the fixed places number
|
|
LOCAL timeFormats IS LIST().
|
|
timeFormats:ADD(LIST(0,LIST("s","m ","h ","d ","y "),2)).
|
|
timeFormats:ADD(LIST(0,LIST("",":",":"," Days, "," Years, "),2)).
|
|
timeFormats:ADD(LIST(0,LIST(" Seconds"," Minutes, "," Hours, "," Days, "," Years, "),2)).
|
|
timeFormats:ADD(LIST(0,LIST("",":",":"),2)).
|
|
timeFormats:ADD(LIST(3,timeFormats[3][1],2)).
|
|
timeFormats:ADD(LIST(2,LIST("s ","m ","h ","d ","y "),0)).
|
|
timeFormats:ADD(LIST(2,LIST(" Seconds "," Minutes "," Hours "," Days "," Years "),0)).
|
|
|
|
LOCAL leading0List IS LIST(2,2,2,3,3).//presumed maximum leading zeros applied to sec,min,hour,day,year values
|
|
|
|
FUNCTION time_formatting {
|
|
PARAMETER timeSec, // the time in seconds to be formatted
|
|
formatType IS 0, // type of format to use, range 0 to 6
|
|
rounding IS 0, // rounding for the seconds place, range 0 to 2
|
|
prependT IS FALSE, // prepend a T- or T+ to format (T- or T if showPlus is FALSE)
|
|
showPlus IS prependT. // by default only display "+" when prependT is TRUE
|
|
|
|
LOCAL timeFormat IS timeFormats[formatType].
|
|
LOCAL fixedPlaces IS timeFormat[0]. // number of required time places (e.g. HH:MM:SS has 3 fixedPlaces)
|
|
LOCAL stringList IS timeFormat[1]. // separators for each time place (must have at least fixedPlaces elements!)
|
|
|
|
// start by rounding the input so we don't have to "carry the one" in time_converter
|
|
LOCAL roundingList IS LIST(MIN(rounding,timeFormat[2]), 0, 0, 0, 0).
|
|
SET timeSec TO ROUND(timeSec, roundingList[0]).
|
|
|
|
LOCAL maxPlaces IS stringList:LENGTH.
|
|
LOCAL timeList IS time_converter(ABS(timeSec), maxPlaces).
|
|
LOCAL maxLength IS MIN(timeList:LENGTH, maxPlaces).
|
|
LOCAL returnString IS "".
|
|
|
|
// fill in missing time places until format is reached
|
|
// e.g. for HH:MM:SS, given 4s, put 0 in HH and MM place
|
|
IF fixedPlaces > 0 {
|
|
UNTIL timeList:LENGTH >= fixedPlaces {
|
|
timeList:ADD(0).
|
|
}
|
|
SET maxLength TO MIN(timeList:LENGTH, maxPlaces).
|
|
} ELSE {
|
|
SET fixedPlaces TO maxLength.
|
|
}
|
|
|
|
// add padding to each element in timeList and prepend to returnString
|
|
FROM {LOCAL i IS maxLength - fixedPlaces.}
|
|
UNTIL i >= maxLength STEP {SET i TO i + 1.} DO {
|
|
LOCAL paddedStr IS padding(timeList[i], leading0List[i], roundingList[i], FALSE, 1).
|
|
SET returnString TO paddedStr + stringList[i] + returnString.
|
|
}
|
|
|
|
// the prependT strings have one space padding
|
|
IF prependT SET returnString TO returnString:INSERT(0, " ").
|
|
|
|
// all time_string formats have either '+','-', or ' ' for padding
|
|
IF timeSec < 0 {
|
|
SET returnString TO returnString:INSERT(0, "-").
|
|
} ELSE IF showPlus {
|
|
SET returnString TO returnString:INSERT(0, "+").
|
|
} ELSE {
|
|
SET returnString TO returnString:INSERT(0, " ").
|
|
}
|
|
|
|
IF prependT SET returnString TO returnString:INSERT(0, "T").
|
|
|
|
RETURN returnString.
|
|
}
|
|
|
|
|
|
LOCAL siPrefixList IS LIST(" y"," z"," a"," f"," p"," n"," μ"," m"," "," k"," M"," G"," T"," P"," E"," Z"," Y").
|
|
|
|
FUNCTION si_formatting {
|
|
PARAMETER num, // number to format, should be in range 10^-24 to 10^24
|
|
unit IS "". // user supplied unit, output will prepend SI prefix
|
|
|
|
IF num = 0 {
|
|
RETURN padding(num,1,3) + " " + unit.
|
|
} ELSE {
|
|
LOCAL powerOfTen IS MAX(MIN(FLOOR(LOG10(ABS(num))),26),-24).
|
|
LOCAL SIfactor IS FLOOR(powerOfTen / 3).
|
|
LOCAL trailingLength IS 3 - (powerOfTen - SIfactor * 3).
|
|
|
|
SET num TO ROUND(num/1000^SIfactor,trailingLength) * 1000^SIfactor.
|
|
|
|
SET powerOfTen TO MAX(MIN(FLOOR(LOG10(ABS(num))),26),-24).
|
|
SET SIfactor TO FLOOR(powerOfTen / 3).
|
|
SET trailingLength TO 3 - (powerOfTen - SIfactor * 3).
|
|
|
|
LOCAL prefix IS siPrefixList[SIfactor + 8].
|
|
RETURN padding(num/1000^SIfactor,1,trailingLength,TRUE,0) + prefix + unit.
|
|
}
|
|
}
|
|
|
|
|
|
LOCAL roundingFunctions IS LIST(ROUND @,FLOOR @,CEILING @).
|
|
|
|
FUNCTION padding {
|
|
PARAMETER num, // number to be formatted
|
|
leadingLength, // minimum digits to the left of the decimal
|
|
trailingLength, // digits to the right of the decimal
|
|
positiveLeadingSpace IS TRUE, // whether to prepend a single space to the output
|
|
roundType IS 0. // 0 for normal rounding, 1 for floor, 2 for ceiling
|
|
|
|
LOCAL returnString IS ABS(roundingFunctions[roundType](num,trailingLength)):TOSTRING.
|
|
|
|
IF trailingLength > 0 {
|
|
IF returnString:CONTAINS(".") {
|
|
LOCAL splitString IS returnString:SPLIT(".").
|
|
SET returnString TO (splitString[0]:PADLEFT(leadingLength) + "." + splitString[1]:PADRIGHT(trailingLength)):REPLACE(" ","0").
|
|
} ELSE {
|
|
SET returnString TO (returnString:PADLEFT(leadingLength) + "." + "0":PADRIGHT(trailingLength)):REPLACE(" ","0").
|
|
}
|
|
} ELSE IF returnString:LENGTH < leadingLength {
|
|
SET returnString TO returnString:PADLEFT(leadingLength):REPLACE(" ","0").
|
|
}
|
|
|
|
IF num < 0 {
|
|
RETURN "-" + returnString.
|
|
} ELSE {
|
|
IF positiveLeadingSpace {
|
|
RETURN " " + returnString.
|
|
} ELSE {
|
|
RETURN returnString.
|
|
}
|
|
}
|
|
} |