Example #1
1
// FormatTimestamp formats t into Postgres' text format for timestamps.
func FormatTimestamp(t time.Time) []byte {
	// Need to send dates before 0001 A.D. with " BC" suffix, instead of the
	// minus sign preferred by Go.
	// Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on
	bc := false
	if t.Year() <= 0 {
		// flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11"
		t = t.AddDate((-t.Year())*2+1, 0, 0)
		bc = true
	}
	b := []byte(t.Format(time.RFC3339Nano))

	_, offset := t.Zone()
	offset = offset % 60
	if offset != 0 {
		// RFC3339Nano already printed the minus sign
		if offset < 0 {
			offset = -offset
		}

		b = append(b, ':')
		if offset < 10 {
			b = append(b, '0')
		}
		b = strconv.AppendInt(b, int64(offset), 10)
	}

	if bc {
		b = append(b, " BC"...)
	}
	return b
}
Example #2
0
func getTimezone(d time.Time, separator bool) string {
	negative := false
	_, tzofs := d.Zone()

	if tzofs < 0 {
		negative = true
		tzofs *= -1
	}

	hours := tzofs / _HOUR
	minutes := tzofs % _HOUR

	switch negative {
	case true:
		if separator {
			return fmt.Sprintf("-%02d:%02d", hours, minutes)
		}

		return fmt.Sprintf("-%02d%02d", hours, minutes)

	default:
		if separator {
			return fmt.Sprintf("+%02d:%02d", hours, minutes)
		}

		return fmt.Sprintf("+%02d%02d", hours, minutes)
	}
}
Example #3
0
// FmtTimeFull returns the full time representation of 't' for 'ko'
func (ko *ko) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	if t.Hour() < 12 {
		b = append(b, ko.periodsAbbreviated[0]...)
	} else {
		b = append(b, ko.periodsAbbreviated[1]...)
	}

	b = append(b, []byte{0x20}...)

	h := t.Hour()

	if h > 12 {
		h -= 12
	}

	b = strconv.AppendInt(b, int64(h), 10)
	b = append(b, []byte{0xec, 0x8b, 0x9c, 0x20}...)
	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, []byte{0xeb, 0xb6, 0x84, 0x20}...)
	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0xec, 0xb4, 0x88, 0x20}...)

	tz, _ := t.Zone()

	if btz, ok := ko.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	return string(b)
}
Example #4
0
File: log.go Project: lucy/go-log
func (log *Logger) date(now time.Time) {
	hour, minute, second := now.Clock()
	year, month, day := now.Date()
	//nsec := now.Nanosecond()
	itoa(&log.buf, year, 4)
	log.buf = append(log.buf, '-')
	itoa(&log.buf, int(month), 2)
	log.buf = append(log.buf, '-')
	itoa(&log.buf, day, 2)
	log.buf = append(log.buf, 'T')
	itoa(&log.buf, hour, 2)
	log.buf = append(log.buf, ':')
	itoa(&log.buf, minute, 2)
	log.buf = append(log.buf, ':')
	itoa(&log.buf, second, 2)
	//log.buf = append(log.buf, '.')
	//itoa(&log.buf, nsec, 9)
	_, off := now.Zone()
	if off == 0 {
		log.buf = append(log.buf, 'Z')
	} else {
		zone := off / 60
		absoff := off
		if zone < 0 {
			log.buf = append(log.buf, '-')
			absoff = -absoff
			zone = -zone
		} else {
			log.buf = append(log.buf, '+')
		}
		itoa(&log.buf, zone/60, 2)
		log.buf = append(log.buf, ':')
		itoa(&log.buf, zone%60, 2)
	}
}
Example #5
0
// FmtTimeFull returns the full time representation of 't' for 'th_TH'
func (th *th_TH) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, []byte{0x20, 0xe0, 0xb8, 0x99, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0xac, 0xe0, 0xb8, 0xb4, 0xe0, 0xb8, 0x81, 0xe0, 0xb8, 0xb2, 0x20}...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, []byte{0x20, 0xe0, 0xb8, 0x99, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0x97, 0xe0, 0xb8, 0xb5, 0x20}...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20, 0xe0, 0xb8, 0xa7, 0xe0, 0xb8, 0xb4, 0xe0, 0xb8, 0x99, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0x97, 0xe0, 0xb8, 0xb5, 0x20}...)

	tz, _ := t.Zone()

	if btz, ok := th.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	return string(b)
}
Example #6
0
// FmtTimeFull returns the full time representation of 't' for 'en_SC'
func (en *en_SC) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	if t.Hour() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, en.timeSeparator...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, en.timeSeparator...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20}...)

	tz, _ := t.Zone()

	if btz, ok := en.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	return string(b)
}
Example #7
0
// FmtTimeLong returns the long time representation of 't' for 'en_SC'
func (en *en_SC) FmtTimeLong(t time.Time) string {

	b := make([]byte, 0, 32)

	if t.Hour() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, en.timeSeparator...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, en.timeSeparator...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20}...)

	tz, _ := t.Zone()
	b = append(b, tz...)

	return string(b)
}
Example #8
0
// FmtTimeFull returns the full time representation of 't' for 'eo'
func (eo *eo) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, []byte{0x2d, 0x61}...)
	b = append(b, []byte{0x20, 0x68, 0x6f, 0x72, 0x6f}...)
	b = append(b, []byte{0x20, 0x6b, 0x61, 0x6a}...)
	b = append(b, []byte{0x20}...)
	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, eo.timeSeparator...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20}...)

	tz, _ := t.Zone()

	if btz, ok := eo.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	return string(b)
}
Example #9
0
// FmtTimeFull returns the full time representation of 't' for 'ja'
func (ja *ja) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, []byte{0xe6, 0x99, 0x82}...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, []byte{0xe5, 0x88, 0x86}...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0xe7, 0xa7, 0x92, 0x20}...)

	tz, _ := t.Zone()

	if btz, ok := ja.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	return string(b)
}
Example #10
0
// FmtTimeLong returns the long time representation of 't' for 'th'
func (th *th) FmtTimeLong(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, []byte{0x20, 0xe0, 0xb8, 0x99, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0xac, 0xe0, 0xb8, 0xb4, 0xe0, 0xb8, 0x81, 0xe0, 0xb8, 0xb2, 0x20}...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, []byte{0x20, 0xe0, 0xb8, 0x99, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0x97, 0xe0, 0xb8, 0xb5, 0x20}...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20, 0xe0, 0xb8, 0xa7, 0xe0, 0xb8, 0xb4, 0xe0, 0xb8, 0x99, 0xe0, 0xb8, 0xb2, 0xe0, 0xb8, 0x97, 0xe0, 0xb8, 0xb5, 0x20}...)

	tz, _ := t.Zone()
	b = append(b, tz...)

	return string(b)
}
Example #11
0
// FmtTimeLong returns the long time representation of 't' for 'sr_Cyrl_RS'
func (sr *sr_Cyrl_RS) FmtTimeLong(t time.Time) string {

	b := make([]byte, 0, 32)

	if t.Hour() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, []byte{0x2e}...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, []byte{0x2e}...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20}...)

	tz, _ := t.Zone()
	b = append(b, tz...)

	return string(b)
}
Example #12
0
// FmtTimeFull returns the full time representation of 't' for 'uz_Arab_AF'
func (uz *uz_Arab_AF) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, uz.timeSeparator...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, uz.timeSeparator...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20, 0x28}...)

	tz, _ := t.Zone()

	if btz, ok := uz.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	b = append(b, []byte{0x29}...)

	return string(b)
}
Example #13
0
// FmtTimeLong returns the long time representation of 't' for 'uz_Latn_UZ'
func (uz *uz_Latn_UZ) FmtTimeLong(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, uz.timeSeparator...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, uz.timeSeparator...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20, 0x28}...)

	tz, _ := t.Zone()
	b = append(b, tz...)

	b = append(b, []byte{0x29}...)

	return string(b)
}
Example #14
0
func appendTimeCommon(dst []byte, t time.Time) []byte {
	_, month, day := t.Date()

	dst = appendTwoDigits(dst, int(month))
	dst = appendTwoDigits(dst, day)

	hour, min, sec := t.Clock()

	dst = appendTwoDigits(dst, hour)
	dst = appendTwoDigits(dst, min)
	dst = appendTwoDigits(dst, sec)

	_, offset := t.Zone()

	switch {
	case offset/60 == 0:
		return append(dst, 'Z')
	case offset > 0:
		dst = append(dst, '+')
	case offset < 0:
		dst = append(dst, '-')
	}

	offsetMinutes := offset / 60
	if offsetMinutes < 0 {
		offsetMinutes = -offsetMinutes
	}

	dst = appendTwoDigits(dst, offsetMinutes/60)
	dst = appendTwoDigits(dst, offsetMinutes%60)

	return dst
}
Example #15
0
// WriteFormattedTime formats t into a format postgres understands.
// Taken with gratitude from pq: https://github.com/lib/pq/blob/b269bd035a727d6c1081f76e7a239a1b00674c40/encode.go#L403
func (pd *Postgres) WriteFormattedTime(buf common.BufferWriter, t time.Time) {
	buf.WriteRune('\'')
	defer buf.WriteRune('\'')
	// XXX: This doesn't currently deal with infinity values

	// Need to send dates before 0001 A.D. with " BC" suffix, instead of the
	// minus sign preferred by Go.
	// Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on
	bc := false
	if t.Year() <= 0 {
		// flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11"
		t = t.AddDate((-t.Year())*2+1, 0, 0)
		bc = true
	}
	buf.WriteString(t.Format(time.RFC3339Nano))

	_, offset := t.Zone()
	offset = offset % 60
	if offset != 0 {
		// RFC3339Nano already printed the minus sign
		if offset < 0 {
			offset = -offset
		}

		buf.WriteRune(':')
		if offset < 10 {
			buf.WriteRune('0')
		}
		buf.WriteString(strconv.FormatInt(int64(offset), 10))
	}

	if bc {
		buf.WriteString(" BC")
	}
}
Example #16
0
func Strftime(format string, t time.Time) (timestamp string, err error) {
	c_format := C.CString(format)
	defer func() { C.free(unsafe.Pointer(c_format)) }()

	tz, offset := t.Zone()
	c_tz := C.CString(tz)
	defer func() { C.free(unsafe.Pointer(c_tz)) }()

	c_time := C.struct_tm{
		tm_year:   C.int(t.Year() - 1900),
		tm_mon:    C.int(t.Month() - 1),
		tm_mday:   C.int(t.Day()),
		tm_hour:   C.int(t.Hour()),
		tm_min:    C.int(t.Minute()),
		tm_sec:    C.int(t.Second()),
		tm_gmtoff: C.long(offset),
		tm_zone:   c_tz,
	}

	c_timestamp, trr := C.ftime(c_format, &c_time)
	defer func() { C.free(unsafe.Pointer(c_timestamp)) }()

	timestamp = C.GoString(c_timestamp)
	if trr == nil {
		timestamp = C.GoString(c_timestamp)
	} else {
		err = fmt.Errorf("%s - %s", trr, t)
	}
	return
}
Example #17
0
// FmtTimeFull returns the full time representation of 't' for 'fr_BE'
func (fr *fr_BE) FmtTimeFull(t time.Time) string {

	b := make([]byte, 0, 32)

	b = strconv.AppendInt(b, int64(t.Hour()), 10)
	b = append(b, []byte{0x20, 0x68}...)
	b = append(b, []byte{0x20}...)

	if t.Minute() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Minute()), 10)
	b = append(b, []byte{0x20, 0x6d, 0x69, 0x6e}...)
	b = append(b, []byte{0x20}...)

	if t.Second() < 10 {
		b = append(b, '0')
	}

	b = strconv.AppendInt(b, int64(t.Second()), 10)
	b = append(b, []byte{0x20, 0x73}...)
	b = append(b, []byte{0x20}...)

	tz, _ := t.Zone()

	if btz, ok := fr.timezones[tz]; ok {
		b = append(b, btz...)
	} else {
		b = append(b, tz...)
	}

	return string(b)
}
Example #18
0
func marshalTimeCommon(out *forkableWriter, t time.Time) (err error) {
	_, month, day := t.Date()

	err = marshalTwoDigits(out, int(month))
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, day)
	if err != nil {
		return
	}

	hour, min, sec := t.Clock()

	err = marshalTwoDigits(out, hour)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, min)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, sec)
	if err != nil {
		return
	}

	_, offset := t.Zone()

	switch {
	case offset/60 == 0:
		err = out.WriteByte('Z')
		return
	case offset > 0:
		err = out.WriteByte('+')
	case offset < 0:
		err = out.WriteByte('-')
	}

	if err != nil {
		return
	}

	offsetMinutes := offset / 60
	if offsetMinutes < 0 {
		offsetMinutes = -offsetMinutes
	}

	err = marshalTwoDigits(out, offsetMinutes/60)
	if err != nil {
		return
	}

	err = marshalTwoDigits(out, offsetMinutes%60)
	return
}
Example #19
0
func strftime(format string, t time.Time) (s string) {
	if format == "" {
		return
	}

	fmt := C.CString(format)
	defer C.free(unsafe.Pointer(fmt))

	// pass timezone to strftime(3) through TZ environment var.

	// XXX: this is not threadsafe; someone may set TZ to a different value
	// between when we get and reset it. we could check that it's unchanged
	// right before setting it back, but that would leave a race between
	// testing and setting, and also a worse scenario where another thread sets
	// TZ to the same value of `zone` as this one (which can't be detected),
	// only to have us unhelpfully reset it to a now-stale value.
	//
	// since a runtime environment where different threads are stomping on TZ
	// is inherently unsafe, don't waste time trying.

	zone, _ := t.Zone()
	oldZone := os.Getenv("TZ")
	if oldZone != zone {
		defer os.Setenv("TZ", oldZone)
		os.Setenv("TZ", zone)
	}

	timep := C.time_t(t.Unix())

	var tm C.struct_tm
	C.localtime_r(&timep, &tm)

	for size := initialBufSize; ; size *= 2 {
		buf := (*C.char)(C.malloc(C.size_t(size))) // can panic
		defer C.free(unsafe.Pointer(buf))
		n := C.strftime(buf, C.size_t(size), fmt, &tm)
		if n == 0 {
			// strftime(3), unhelpfully: "Note that the return value 0 does not
			// necessarily indicate an error; for example, in many locales %p
			// yields an empty string." This leaves no definite way to
			// distinguish between the cases where the value doesn't fit and
			// where it does because the string is empty. In the latter case,
			// allocating increasingly larger buffers will never change the
			// result, so we need some heuristic for bailing out.
			//
			// Since a single 2-byte conversion sequence should not produce an
			// output longer than about 24 bytes, we conservatively allow the
			// buffer size to grow up to 20 times larger than the format string
			// before giving up.
			if size > 20*len(format) {
				return
			}
		} else if int(n) < size {
			s = C.GoStringN(buf, C.int(n))
			return
		}
	}
	return
}
Example #20
0
// WriteTime writes a time.Time in a byte-sortable way.
//
// This method truncates the time to microseconds and drops the timezone,
// because that's the (undocumented) way that the appengine SDK does it.
func WriteTime(buf Buffer, t time.Time) error {
	name, off := t.Zone()
	if name != "UTC" || off != 0 {
		panic(fmt.Errorf("helper: UTC OR DEATH: %s", t))
	}
	_, err := cmpbin.WriteUint(buf, uint64(t.Unix())*1e6+uint64(t.Nanosecond()/1e3))
	return err
}
Example #21
0
// WriteTime writes a time.Time to the buffer.
//
// The supplied time is rounded via datastore.RoundTime and written as a
// microseconds-since-epoch integer to comform to datastore storage standards.
func WriteTime(buf Buffer, t time.Time) error {
	name, off := t.Zone()
	if name != "UTC" || off != 0 {
		panic(fmt.Errorf("helper: UTC OR DEATH: %s", t))
	}

	_, err := cmpbin.WriteInt(buf, ds.TimeToInt(t))
	return err
}
Example #22
0
// IsZoneKnown reports whether t is in a known timezone.
// Camlistore uses the magic timezone offset of 1 minute west of UTC
// to mean that the timezone wasn't known.
func IsZoneKnown(t time.Time) bool {
	if t.Location() == UnknownLocation {
		return false
	}
	if _, off := t.Zone(); off == -60 {
		return false
	}
	return true
}
Example #23
0
func toISO8601(t time.Time) string {
	var tz string
	name, offset := t.Zone()
	if name == "UTC" {
		tz = "Z"
	} else {
		tz = fmt.Sprintf("%03d00", offset/3600)
	}
	return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
}
Example #24
0
func EncodeDateProperty(name string, t time.Time) string {
	var output string
	zone, _ := t.Zone()
	if zone != "UTC" && zone != "" {
		output = ";TZID=" + zone + ":" + t.Format("20060102T150405")
	} else {
		output = ":" + t.Format("20060102T150405") + "Z"
	}
	return name + output
}
Example #25
0
func EncodeAllDayDateProperty(name string, t time.Time) string {
	var output string
	zone, _ := t.Zone()
	if zone != "UTC" && zone != "" {
		output = ";TZID=" + zone + ";VALUE=DATE:" + t.Format("20060102")
	} else {
		output = ";VALUE=DATE:" + t.Format("20060102")
	}
	return name + output
}
Example #26
0
// ISO8601 returns an ISO 6801 formatted string from a time.
func ISO8601(t time.Time) string {
	var tz string
	if zone, offset := t.Zone(); zone == "UTC" {
		tz = "Z"
	} else {
		tz = fmt.Sprintf("%03d00", offset/3600)
	}
	return fmt.Sprintf("%04d-%02d-%02dT%02d:%02d:%02d%s",
		t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), tz)
}
Example #27
0
// SetLocation updates the location of the given time,
// while preserving the time values (day, hour, minutes, etc.)
func SetLocation(l *time.Location, t *time.Time) {
	if l == nil {
		l = time.UTC
	}
	_, z1 := t.Zone()
	ll := t.Location()
	*ll = *l
	_, z2 := t.Zone()
	d := int64(time.Second) * int64(z1-z2)
	*t = t.Add(time.Duration(d))
}
Example #28
0
// Apply timezone to world time
func applyTimezone(worldTime float64, date time.Time) float64 {
	_, tzoffsetMinutes := date.Zone()
	offset := float64(tzoffsetMinutes / 3600)

	if t := worldTime + offset; t < 0.0 {
		return t + 24.0
	} else if t >= 24.0 {
		return t - 24.0
	} else {
		return t
	}
}
Example #29
0
// Strftime formats time according to the directives in the given format string. Any text not listed as a directive will be
// passed through to the output string.
//
// Format meanings:
//
//		[%a]   The abbreviated weekday name (۳ش)
//		[%A]   The full weekday name (یکشنبه)
//		[%b]   The month name (اردیبهشت)
//		[%B]   The month name in pinglish (Ordibehesht)
//		[%d]   Day of the month (01..31)
//		[%e]   Day of the month (1..31)
//		[%j]   Day of the year (1..366)
//		[%m]   Month of the year, zero-padded (01..12)
//		[%_m]  Month of the year, blank-padded ( 1..12)
//		[%-m]  Month of the year, no-padded (1..12)
//		[%w]   Day of the week (Sunday is 0, 0..6)
//		[%x]   Preferred representation for the date alone, no time in format YY/M/D
//		[%y]   Year without a century (00..99)
//		[%Y]   Year with century
//		[%H]   Hour of the day, 24-hour clock (00..23)
//		[%I]   Hour of the day, 12-hour clock (01..12)
//		[%M]   Minute of the hour (00..59)
//		[%p]   Meridian indicator ("بعد از ظهر" or "قبل از ظهر")
//		[%S]   Second of the minute (00..60)
//		[%x]   1392/04/02
//		[%-x]  92/4/2
//		[%X]   Preferred representation for the time alone, no date
//		[%Z]   Time zone name
//		[%%]   Literal %'' character
//
// Example:
// 		jalali.Strftime("Printed on %Y/%m/%d", time.Now())   #=> "Printed on 1392/04/02"
func Strftime(format string, t time.Time) string {
	jyear, jmonth, jday := Gtoj(t)
	output := format
	yy := fmt.Sprintf("%d", jyear)[2:]
	hh := t.Hour()
	if t.Hour() >= 12 {
		hh = t.Hour() - 12
	}
	ampm := persianMeridianIndicatorShort[0]
	if t.Hour() >= 12 {
		ampm = persianMeridianIndicatorShort[1]
	}
	AMPM := persianMeridianIndicator[0]
	if t.Hour() >= 12 {
		AMPM = persianMeridianIndicator[1]
	}

	zone, _ := t.Zone()

	// X:=[("%02d" % @hour),("%02d" % @min),("%02d" % @sec)].join(":"))
	re := [][]string{
		{"%%", "SUBSTITUTION_MARKER"},
		{"%m", fmt.Sprintf("%02d", jmonth)},
		{"%_m", fmt.Sprintf("% 2d", jmonth)},
		{"%-m", fmt.Sprintf("%d", jmonth)},
		{"%a", persianWeekdayNamesShort[t.Weekday()]},
		{"%A", persianWeekdayNames[t.Weekday()]},
		{"%b", persianMonthNames[jmonth]},
		{"%B", persianMonthNamesPEnglish[jmonth]},
		{"%d", fmt.Sprintf("%02d", jday)},
		{"%e", fmt.Sprintf("%d", jday)},
		{"%Y", fmt.Sprintf("%d", jyear)},
		{"%y", yy},
		{"%j", fmt.Sprintf("%d", t.YearDay())},
		{"%H", fmt.Sprintf("%02d", t.Hour())},
		{"%I", fmt.Sprintf("%02d", hh)},
		{"%M", fmt.Sprintf("%02d", t.Minute())},
		{"%S", fmt.Sprintf("%02d", t.Second())},
		{"%p", ampm},
		{"%P", AMPM},
		{"%w", fmt.Sprintf("%d", t.Weekday())},
		{"%Z", zone},
		{"%X", fmt.Sprintf("%02d:%02d:%02d", t.Hour(), t.Minute(), t.Second())},
		{"%x", fmt.Sprintf("%d/%02d/%02d", jyear, t.Month(), t.Day())},
		{"%-x", fmt.Sprintf("%s/%d/%d", yy, t.Month(), t.Day())},
		{"SUBSTITUTION_MARKER", "%"},
	}
	for _, r := range re {
		output = strings.Replace(output, r[0], r[1], -1)
	}
	return output
}
func (l *UdpDimLamp) writeTime(t time.Time, buf *bytes.Buffer) {
	unix := t.Unix()
	_, offset := t.Zone()
	local := unix + int64(offset)
	buf.WriteByte(byte(local >> 56))
	buf.WriteByte(byte((local >> 48) & 0xff))
	buf.WriteByte(byte((local >> 40) & 0xff))
	buf.WriteByte(byte((local >> 32) & 0xff))
	buf.WriteByte(byte((local >> 24) & 0xff))
	buf.WriteByte(byte((local >> 16) & 0xff))
	buf.WriteByte(byte((local >> 8) & 0xff))
	buf.WriteByte(byte(local & 0xff))
}