Get 12 hour from time in Go - go

Go noob here, and all I want to do is use the time format constants list https://golang.org/src/time/format.go that are mentioned in 3 posts here on SO (https://stackoverflow.com/a/20234207 https://stackoverflow.com/a/14106561 https://stackoverflow.com/a/20234207). None of which including the docs (at least that I can tell) have an example of how to use them.
I would expect this to work (but it clearly does not):
t := time.Now()
log.Println(t.stdHour12())
Can you please tell me how to get only the hour (in 12 hour time) for a given time t (ex: 10 from 2021-03-09 22:45:04.009063861 -0500 EST)?
const (
stdLongMonth = "January"
stdMonth = "Jan"
stdNumMonth = "1"
stdZeroMonth = "01"
stdLongWeekDay = "Monday"
stdWeekDay = "Mon"
stdDay = "2"
stdUnderDay = "_2"
stdZeroDay = "02"
stdHour = "15"
stdHour12 = "3"
stdZeroHour12 = "03"
stdMinute = "4"
stdZeroMinute = "04"
stdSecond = "5"
stdZeroSecond = "05"
stdLongYear = "2006"
stdYear = "06"
stdPM = "PM"
stdpm = "pm"
stdTZ = "MST"
stdISO8601TZ = "Z0700" // prints Z for UTC
stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
stdNumTZ = "-0700" // always numeric
stdNumShortTZ = "-07" // always numeric
stdNumColonTZ = "-07:00" // always numeric
)
Thanks in advance!
EDIT: From the answers received so far, I see that I cannot use the constants above to achieve what I want so I changed the wording of this question to specifically ask to return the hour (and just the hour) for a given time.

The Time object specifies the full date and time. You can extract just the time, if you like:
func main() {
t := time.Now()
fmt.Println(t.Format(time.Kitchen))
}
time.Kitchen is defined in the time package as Kitchen = "3:04PM"
If you want to understand how the format is interpreted, read this piece of documentation carefully
If you just need the hour, call the Hour() method on a Time object. If you want it in 12-hour format, you can just do modulo 12:
func main() {
t := time.Now()
fmt.Println(t.Hour())
fmt.Println(t.Hour() % 12)
}

These are constants representing tokens used internally by formatting code in time package (note they start with lower letter so they aren't exported and you can't even use them outside time package).
If you want to come up with your own format in Go (for both parsing and output) you simply define it using these tokens "as example" and Format() will parse it and apply that format (if valid) to itself.
const (
MyLayout = "3"
)
func main() {
t := time.Now()
fmt.Println(t.Format(MyLayout))
}
Available tokens are listed for example here.

Related

Having trouble with comparing datetimes, when there are DB, Golang and Unix versions

So, basically a person has a shift, with a start time and duration, and I need to know how many minutes to go.
I retrieve from the database (mySQL) a standard string of datetime for the start of the shift (eg. 2022-01-01 09:00:00)
I also retrieve the number of hours of the shift (eg. 8)
I can then determine current time, using Golang's Time.time, but this format is different.
Please see code below, which explains the problem better, and gives the pieces missing.
Thanks!
var shiftStartDB string // For example 2022-01-01 09:00:00
var shiftStartUnix int // For example, start time converted to minutes since epoch
var offTimer int // Number of hours for the shift
var shiftEndDB string // For example 2022-01-01 17:00:00
var shiftEndUnix int // For example, end time converted to minutes since epoch
var nowTime Time.time // Golangs version of time for now
var nowUnix int // Golang now converted to Unix time
var templateID string
var minsToGo int
_ = db.QueryRow("SELECT LastSignedOn, OffTimer, TemplateID FROM assets WHERE ID = ?", assetid).Scan(&shiftStartDB, &offTimer, &templateID)
shiftStartUnix = <convert database time into unix time>
if offTimerTemp == 0 {
_ = db.QueryRow("OffTimer FROM templates WHERE ID = ?", templateID).Scan(&offTimer)
}
shiftEndUnix = shiftStartUnix + (offTimer * 60)
nowTime = time.Now()
nowUnix = <convert golang time into unix time>
minsToGo = shiftEndInt - nowInt
You can use nowUnix = nowTime.UNIX()/60, as Time.UNIX returns the number of seconds elapsed since epoch. that said, this might be easier to deal with if you parsed the times and used go library time functions directly:
shiftStartTime,err := time.Parse("2006-02-01 15:04:05",dbTime)
shiftEnd=shiftStartTime.Add(time.Hour*offTimer)
minsToGo:=shiftEnd.Sub(time.Now()).Minutes()

Parse log entries with least possible overhead

I have some log format with entries like this:
log_entry_no1 := "2021-11-03 7:7:51 hal9000 evil_app heartbeat C99 I am sorry Dave"
Those "fields" are separated by space except the last one called message which is just log data and can contain spaces.
My question is. Is there better way to process those entries without first splitting whole sentence and then join'ing that last part (message) with less overhead using go?
type LogData struct {
d Date // yyyy-mm-dd Mandatory
t Time // hh:mm:ss Mandatory
hostname string // Mandatory
app_id string // Mandatory
etype string // enum based string Mandatory
level string // Optional base on etype
message string // Mandatory
}
log_fields := strings.Split(log_entry_no1, " ")
var log_data = LogData{}
log_data.d = parseTime(log_entry_no1[0])
log_data.t = parseTime(log_entry_no1[1])
//...
if log_fields[4] == "heartbeat" {
log_data.level = log_fields[5]
log_data.message = strings.Join(log_fields[6:], " ")
} else {
log_data.message = strings.Join(log_fields[5:], " ")
}
Use strings.SplitN.
func SplitN(s, sep string, n int) []string
The docs say if n is greater than zero: it returns at most n substrings; the last substring will be the unsplit remainder.

Displaying float to a variable number of decimal places in Swift

Is there a simple way of displaying a float or double to a relevant number of decimal places in Swift.
For example, an iOS app using SI units, which can be altered depending on the property desired, and converted through up to 6 orders of magnitude depending on desired inputs and output. Therefore it needs to display not only 1mg to 1000 micrograms, but also the other way around - i.e 1 microgram = 0.001 mg.
I can easily format a string as follows:
textFieldFoo.text = NSString(format: "%.1f mg", bar) as String
However, if the user were to convert from 1mcg to 0.001mg, this would display as
0.0 mg
Yet, to include up to 6 decimal places to encompass all common possibilities would lead to an unwieldy, ugly looking UI.
Is there a simple way to format a string, in order to include a float/ double where it is displayed to a relevant number of decimal places/ significant figures? I'm sure, given time and enough boilerplate code, that I could pyramid if/ else it to get a result, but that's frankly inelegant.
There's NSMAssFormatter but it doesn't go all the way down to microgram. It was designed to format human-level weight.
You can roll your own by subclassing NSNumberFormatter:
enum MassUnit: Double {
case Microgram = 1e-6
case Milligram = 1e-3
case Gram = 1
case Kilogram = 1e3
static let allUnits: [MassUnit] = [.Microgram, .Milligram, .Gram, .Kilogram]
var unitAbbreviation: String {
get {
switch self {
case .Microgram: return "mcg"
case .Milligram: return "mg"
case .Gram: return "g"
case .Kilogram: return "kg"
}
}
}
}
class MyMassFormatter: NSNumberFormatter {
func bestFitStringForWeightInGrams(weight: Double) -> String {
var selectedString = self.stringFromNumber(weight)!
var selectedUnit = MassUnit.Gram
// Pick the unit that results in the shortest string
for unit in MassUnit.allUnits {
if let str = self.stringFromNumber(weight / unit.rawValue)
where str.characters.count < selectedString.characters.count {
selectedString = str
selectedUnit = unit
}
}
return selectedString + selectedUnit.unitAbbreviation
}
}
Usage:
let formatter = MyMassFormatter()
formatter.format = "0.######"
print(formatter.bestFitStringForWeightInGrams(0.000001)) // 1mcg
print(formatter.bestFitStringForWeightInGrams(0.005)) // 5mg
print(formatter.bestFitStringForWeightInGrams(2500)) // 2.5kg
print(formatter.bestFitStringForWeightInGrams(1234.5)) // 1234.5g
Formatting to Significant Figures using Swift
What you want is the ability to format to a fixed number of significant figures, rather than a fixed number of decimal places. A good swift option to solve this is using class extensions, with a little maths to decide how many decimal places to show based on the magnitude of the number.
The example below extends the Double class to enable formatting to a fixed number of significant figures and uses either float notation or scientific notation depending on the magnitude of the number.
import Foundation
//extension to format a Double to a fixed number of significant figures
extension Double {
func sigFigs(_ numberOfSignificantFigures: Int) -> String {
let mag = log10(abs(self))
let intMag = Int(mag)
if mag >= 0 {
if intMag < numberOfSignificantFigures {
return String(format: "%.\(numberOfSignificantFigures - intMag - 1)f",self)
}
else {
return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
}
}
else {
if -intMag < numberOfSignificantFigures {
return String(format: "%.\(numberOfSignificantFigures)f",self)
}
else {
return String(format: "%.\(numberOfSignificantFigures - 1)e",self)
}
}
}
}
Usage
let num1 = 1234.5678
let num2 = 12.345678
let num3 = 0.0012345678
let num4 = 1234567.8
print(num1.sigFigs(6))
print(num1.sigFigs(2))
print(num2.sigFigs(6))
print(num2.sigFigs(2))
print(num3.sigFigs(6))
print(num3.sigFigs(2))
print(num4.sigFigs(6))
print(num4.sigFigs(2))
Output
1234.57
1.2e+03
12.3457
12
0.001235
1.2e-03
1.23457e+06
1.2e+06
If I understand you correctly you are:
using Swift
working with SI units
trying to display floating points
trying to avoid boilerplate and possibly magic numbers
You should definitely use Apple's Measurement which is :
A numeric quantity labeled with a unit of measure, with support for unit conversion and unit-aware calculations.
and MeasurementFormatter which is :
A formatter that provides localized representations of units and measurements.
MeasurementFormatter uses a NumberFormatter to format the quantity of a measurement.
NumberFormatters's usesSignificantDigits property is set to false by default but :
Set this property to true to format numbers according to the significant digits configuration specified by the minimumSignificantDigits and maximumSignificantDigits properties. By default, the minimum number of significant digits is 1, and the maximum number of significant digits is 6.
Here's an example of what you can do with masses
let micrograms = Measurement(value: 1, unit: UnitMass.micrograms) // 1.0 µg
let nanograms = micrograms.converted(to: .nanograms) // 1000.0000000000001 ng
let picograms = micrograms.converted(to: .picograms) // 1000000.0 pg
let milligrams = micrograms.converted(to: .milligrams) // 0.001 mg
let centigrams = micrograms.converted(to: .centigrams) // 0.0001 cg
let decigrams = micrograms.converted(to: .decigrams) // 1e-05 dg
let grams = micrograms.converted(to: .grams) // 1e-06 g
let kilograms = micrograms.converted(to: .kilograms) // 1e-09 kg
let ounces = micrograms.converted(to: .ounces) // 3.527399072294044e-08 oz
let pounds = micrograms.converted(to: .pounds) // 2.2046244201837776e-09 lb
let stones = micrograms.converted(to: .stones) // 1.574731232746851e-10 st
let formatter = MeasurementFormatter()
formatter.numberFormatter.usesSignificantDigits = true
formatter.unitOptions = .providedUnit
formatter.string(from: nanograms) // "1 000 ng"
formatter.string(from: picograms) // "1 000 000 pg"
formatter.string(from: micrograms) // "1 µg"
formatter.string(from: milligrams) // "0,001 mg"
formatter.string(from: centigrams) // "0,0001 cg"
formatter.string(from: decigrams) // "0,00001 dg"
formatter.string(from: grams) // "0,000001 g"
formatter.string(from: kilograms) // "0,000000001 kg"
formatter.string(from: ounces) // "0,000000035274 oz"
formatter.string(from: pounds) // "0,00000000220462 lb"
formatter.string(from: stones) // "0,000000000157473 st"

R: tm Textmining package: Doc-Level metadata generation is slow

I have a list of documents to process, and for each record I want to attach some metadata to the document "member" inside the "corpus" data structure that tm, the R package, generates (from reading in text files).
This for-loop works but it is very slow,
Performance seems to degrade as a function f ~ 1/n_docs.
for (i in seq(from= 1, to=length(corpus), by=1)){
if(opts$options$verbose == TRUE || i %% 50 == 0){
print(paste(i, " ", substr(corpus[[i]], 1, 140), sep = " "))
}
DublinCore(corpus[[i]], "title") = csv[[i,10]]
DublinCore(corpus[[i]], "Publisher" ) = csv[[i,16]] #institutions
}
This may do something to the corpus variable but I don't know what.
But when I put it inside a tm_map() (similar to lapply() function), it runs much faster, but the changes are not made persistent:
i = 0
corpus = tm_map(corpus, function(x){
i <<- i + 1
if(opts$options$verbose == TRUE){
print(paste(i, " ", substr(x, 1, 140), sep = " "))
}
meta(x, tag = "Heading") = csv[[i,10]]
meta(x, tag = "publisher" ) = csv[[i,16]]
})
Variable corpus has empty metadata fields after exiting the tm_map function. It should be filled. I have a few other things to do with the collection.
The R documentation for the meta() function says this:
Examples:
data("crude")
meta(crude[[1]])
DublinCore(crude[[1]])
meta(crude[[1]], tag = "Topics")
meta(crude[[1]], tag = "Comment") <- "A short comment."
meta(crude[[1]], tag = "Topics") <- NULL
DublinCore(crude[[1]], tag = "creator") <- "Ano Nymous"
DublinCore(crude[[1]], tag = "Format") <- "XML"
DublinCore(crude[[1]])
meta(crude[[1]])
meta(crude)
meta(crude, type = "corpus")
meta(crude, "labels") <- 21:40
meta(crude)
I tried many of these calls (with var "corpus" instead of "crude"), but they do not seem to work.
Someone else once seemed to have had the same problem with a similar data set (forum post from 2009, no response)
Here's a bit of benchmarking...
With the for loop :
expr.for <- function() {
for (i in seq(from= 1, to=length(corpus), by=1)){
DublinCore(corpus[[i]], "title") = LETTERS[round(runif(26))]
DublinCore(corpus[[i]], "Publisher" ) = LETTERS[round(runif(26))]
}
}
microbenchmark(expr.for())
# Unit: milliseconds
# expr min lq median uq max
# 1 expr.for() 21.50504 22.40111 23.56246 23.90446 70.12398
With tm_map :
corpus <- crude
expr.map <- function() {
tm_map(corpus, function(x) {
meta(x, "title") = LETTERS[round(runif(26))]
meta(x, "Publisher" ) = LETTERS[round(runif(26))]
x
})
}
microbenchmark(expr.map())
# Unit: milliseconds
# expr min lq median uq max
# 1 expr.map() 5.575842 5.700616 5.796284 5.886589 8.753482
So the tm_map version, as you noticed, seems to be about 4 times faster.
In your question you say that the changes in the tm_map version are not persistent, it is because you don't return x at the end of your anonymous function. In the end it should be :
meta(x, tag = "Heading") = csv[[i,10]]
meta(x, tag = "publisher" ) = csv[[i,16]]
x

Accessing position information in a scala combinatorparser kills performance

I wrote a new combinator for my parser in scala.
Its a variation of the ^^ combinator, which passes position information on.
But accessing the position information of the input element really cost performance.
In my case parsing a big example need around 3 seconds without position information, with it needs over 30 seconds.
I wrote a runnable example where the runtime is about 50% more when accessing the position.
Why is that? How can I get a better runtime?
Example:
import scala.util.parsing.combinator.RegexParsers
import scala.util.parsing.combinator.Parsers
import scala.util.matching.Regex
import scala.language.implicitConversions
object FooParser extends RegexParsers with Parsers {
var withPosInfo = false
def b: Parser[String] = regexB("""[a-z]+""".r) ^^# { case (b, x) => b + " ::" + x.toString }
def regexB(p: Regex): BParser[String] = new BParser(regex(p))
class BParser[T](p: Parser[T]) {
def ^^#[U](f: ((Int, Int), T) => U): Parser[U] = Parser { in =>
val source = in.source
val offset = in.offset
val start = handleWhiteSpace(source, offset)
val inwo = in.drop(start - offset)
p(inwo) match {
case Success(t, in1) =>
{
var a = 3
var b = 4
if(withPosInfo)
{ // takes a lot of time
a = inwo.pos.line
b = inwo.pos.column
}
Success(f((a, b), t), in1)
}
case ns: NoSuccess => ns
}
}
}
def main(args: Array[String]) = {
val r = "foo"*50000000
var now = System.nanoTime
parseAll(b, r)
var us = (System.nanoTime - now) / 1000
println("without: %d us".format(us))
withPosInfo = true
now = System.nanoTime
parseAll(b, r)
us = (System.nanoTime - now) / 1000
println("with : %d us".format(us))
}
}
Output:
without: 2952496 us
with : 4591070 us
Unfortunately, I don't think you can use the same approach. The problem is that line numbers end up implemented by scala.util.parsing.input.OffsetPosition which builds a list of every line break every time it is created. So if it ends up with string input it will parse the entire thing on every call to pos (twice in your example). See the code for CharSequenceReader and OffsetPosition for more details.
There is one quick thing you can do to speed this up:
val ip = inwo.pos
a = ip.line
b = ip.column
to at least avoid creating pos twice. But that still leaves you with a lot of redundant work. I'm afraid to really solve the problem you'll have to build the index as in OffsetPosition yourself, just once, and then keep referring to it.
You could also file a bug report / make an enhancement request. This is not a very good way to implement the feature.

Resources