Help us shape the future of Go! Take the 2026 Go Developer Survey

nepdate

package module
v0.1.0-beta.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 21, 2026 License: MIT Imports: 5 Imported by: 0

README

NepDate for Go logo

nepdate-go

CI Go Reference Release

Bikram Sambat (Nepali) calendar for Go. Part of the NepDate family: shared data and the behaviour spec live in the hub sanamhub/nepdate; the C# original is NepDate.

Status: 0.1.0-beta.1, the first public pre-release. The API is listed in docs/API.md and may still change before 0.1.0. Patro data (tithi, holidays, events) is informational, not an official calendar.

Go 1.24 or later. CI runs the tests on Go 1.24.13 and the full gates on Go 1.26 and 1.27.

  • Package nepdate, module github.com/sanamhub/nepdate-go. Patro (पात्रो, the Nepali almanac: tithi, public holidays and events) is the package github.com/sanamhub/nepdate-go/patro of the same module. The core never imports it, so a program that only converts dates links no patro data.
  • Zero dependencies. Zero allocations on conversion, arithmetic, comparison, successful parsing, Append* formatting and patro lookups (measured with -benchmem).
  • BS 1901-01-01 to 2199-12-30 (AD 1844-04-11 to 2143-04-15). Patro data covers BS 2077-01-01 to 2084-08-20. Same results as C# NepDate and the other ports, except the deviations in shared/spec/PARITY.md.

Install

go get github.com/sanamhub/nepdate-go@v0.1.0-beta.1
import (
	"github.com/sanamhub/nepdate-go"       // package nepdate
	"github.com/sanamhub/nepdate-go/patro" // only if you need tithi, holidays or events
)

Package docs: https://pkg.go.dev/github.com/sanamhub/nepdate-go

Quick start

The snippets use fmt, log and time from the standard library, plus the imports above. Construct a BS date and read its Gregorian date:

	d, err := nepdate.New(2081, nepdate.Shrawan, 32)
	if err != nil {
		log.Fatal(err)
	}
	y, m, day := d.Gregorian()
	fmt.Println(y, int(m), day)

Format in Nepali:

	d, _ := nepdate.New(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Format("MMM d, yyyy", nepdate.Nepali))

Append a long form without allocating:

	d, _ := nepdate.New(2081, nepdate.Shrawan, 15)
	var buf []byte
	buf = d.AppendLong(buf, nepdate.LongOptions{Weekday: true}, nepdate.Nepali)
	fmt.Println(string(buf))

Parse what a person wrote:

	d, err := nepdate.ParseLenient("15 Shrawan 2080")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(d)

Convert a Go time:

	d, err := nepdate.FromTime(time.Date(2024, time.August, 16, 0, 0, 0, 0, time.UTC))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(d)

Read the almanac for a date:

	d, _ := nepdate.New(2081, nepdate.Baishakh, 1)
	i := patro.Of(d)
	t, _ := i.Tithi()
	fmt.Println(t.Name(nepdate.Nepali), i.IsPublicHoliday())
	for n := 0; n < i.EventCount(); n++ {
		fmt.Println(i.Event(n).Name(nepdate.English))
	}

A Date marshals to JSON as "YYYY-MM-DD". Saving an unset (zero) Date returns an error, so use *Date for an optional field; nil marshals as null.

More

Topic Where
Every exported identifier docs/API.md
Speed and allocations, with the C# baseline docs/benchmarks.md
What changed in each version CHANGELOG.md
Building, gates and pull requests CONTRIBUTING.md
Reporting a vulnerability SECURITY.md
A wrong date, holiday or tithi the hub's data error form
The other languages sanamhub/nepdate

License

MIT (LICENSE). Calendar data from NepDate by Raju Prasai and contributors, MIT (shared/data/NOTICE). Not affiliated with the Government of Nepal.

Documentation

Overview

Package nepdate converts between the Bikram Sambat (Nepali) and Gregorian calendars, and formats, parses and does arithmetic on BS dates.

The supported range is BS 1901-01-01 to 2199-12-30 (AD 1844-04-11 to 2143-04-15). Dates outside it return ErrOutOfRange. The zero Date is "no date": IsZero reports true and every operation that can fail returns ErrOutOfRange.

Import it as

import nepdate "github.com/sanamhub/nepdate-go"

Tithi, public holidays and events live in the separate package github.com/sanamhub/nepdate-go/patro. This package never imports it, so a program that only converts dates links none of the patro data.

A Date marshals to JSON as "YYYY-MM-DD". Marshalling the zero Date returns ErrOutOfRange, so an optional date should be a *Date: nil marshals as null.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	Min = Date{1901, 1, 1}
	Max = Date{2199, 12, 30}
)

Min and Max are the first and last supported dates, BS 1901-01-01 and 2199-12-30.

View Source
var (
	// ErrOutOfRange reports a date outside BS 1901-01-01..2199-12-30, a Gregorian date outside
	// AD 1844-04-11..2143-04-15, an operation whose result leaves the range, or the zero Date.
	ErrOutOfRange = errors.New("nepdate: date outside BS 1901-01-01..2199-12-30")
	// ErrInvalidMonth reports a month outside 1..12.
	ErrInvalidMonth = errors.New("nepdate: month must be 1..12")
	// ErrInvalidDay reports a day outside 1 to the length of its month.
	ErrInvalidDay = errors.New("nepdate: day outside the month")
	// ErrInvalidGregorian reports an AD date that does not exist, such as 2023-02-29.
	ErrInvalidGregorian = errors.New("nepdate: invalid Gregorian date")
)

Sentinel errors. Test for them with errors.Is.

Functions

func WeekdayName

func WeekdayName(w time.Weekday, lang Lang) string

WeekdayName returns the full name of w in lang, or "" if w is not Sunday..Saturday or lang is unknown. It does not allocate.

Example
package main

import (
	"fmt"
	"time"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	fmt.Println(nepdate.WeekdayName(time.Tuesday, nepdate.English))
	fmt.Println(nepdate.WeekdayName(time.Tuesday, nepdate.Nepali))
}
Output:
Tuesday
मङ्गलवार

func WeekdayShortName

func WeekdayShortName(w time.Weekday, lang Lang) string

WeekdayShortName returns the short name of w in lang ("Tue", "मङ्गल"), or "" if w is not Sunday..Saturday or lang is unknown. It does not allocate.

Example
package main

import (
	"fmt"
	"time"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	fmt.Println(nepdate.WeekdayShortName(time.Tuesday, nepdate.English))
	fmt.Println(nepdate.WeekdayShortName(time.Tuesday, nepdate.Nepali))
}
Output:
Tue
मङ्गल

Types

type Date

type Date struct {
	// contains filtered or unexported fields
}

Date is a Bikram Sambat calendar date. It is a small comparable value: use == and as a map key. The zero value is "no date" (PARITY D-01): IsZero reports true, accessors return 0, and every operation that returns an error returns ErrOutOfRange.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	y, m, day := d.Gregorian()
	fmt.Println(d.Year(), d.Month(), d.Day(), d.Weekday())
	fmt.Println(y, int(m), day)
}
Output:
2081 Shrawan 15 Tuesday
2024 7 30

func FromGregorian

func FromGregorian(year int, month time.Month, day int) (Date, error)

FromGregorian returns the BS date of the AD date year-month-day. It returns ErrInvalidGregorian if that AD date does not exist (2023-02-29) and ErrOutOfRange if it is outside AD 1844-04-11..2143-04-15, checked in that order (ALGORITHM §3). It does not allocate.

Example
package main

import (
	"fmt"
	"log"
	"time"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, err := nepdate.FromGregorian(2024, time.August, 16)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(d)
}
Output:
2081/04/32

func FromTime

func FromTime(t time.Time) (Date, error)

FromTime returns the BS date of t's calendar date in t's own location. FromTime(t) and FromTime(t.UTC()) can differ by a day: Nepal is UTC+05:45, so 2024-07-30 18:30 UTC is already 2024-07-31 in Kathmandu (BS 2081-04-16, against 2081-04-15 in UTC). Convert t with In first to get the date somewhere else. It returns ErrOutOfRange outside AD 1844-04-11..2143-04-15. It does not allocate.

Example
package main

import (
	"fmt"
	"log"
	"time"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, err := nepdate.FromTime(time.Date(2024, time.August, 16, 0, 0, 0, 0, time.UTC))
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(d)
}
Output:
2081/04/32

func MustNew

func MustNew(year int, month Month, day int) Date

MustNew is New for constants and tests. It panics with New's error.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(d)
}
Output:
2081/04/15

func New

func New(year int, month Month, day int) (Date, error)

New returns the date year-month-day. It checks the year first, then the month, then the day (ALGORITHM §3), and returns ErrOutOfRange for a year outside 1901..2199, ErrInvalidMonth for a month outside 1..12 and ErrInvalidDay for a day outside the month. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, err := nepdate.New(2081, nepdate.Shrawan, 32)
	if err != nil {
		log.Fatal(err)
	}
	y, m, day := d.Gregorian()
	fmt.Println(y, int(m), day)
}
Output:
2024 8 16

func Parse

func Parse(s string) (Date, error)

Parse reads a date in the strict form of shared/spec/PARSING.md §1: year, month and day in that order, ASCII or Devanagari digits (they may be mixed, PARITY D-05), at most 4 digits per number, separated by any of - / . _ \ space । |. It returns a *ParseError when the text is not in that form, and New's error when it names an invalid date. It does not allocate on success; a failed call allocates one *ParseError.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, err := nepdate.Parse("2081-04-15")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(d, d.Weekday())
}
Output:
2081/04/15 Tuesday

func ParseLenient

func ParseLenient(s string) (Date, error)

ParseLenient reads a date written by a person (shared/spec/PARSING.md §2), such as "15 Shrawan 2080", "Shrawan 15, 2080", "१५ श्रावण २०८०" or "15.04.2080". It tries Parse first. Otherwise it splits the text into numbers and words, drops era markers (BS, वि.सं.) and the words गते and मिति, and accepts a closed list of month names (PARSING §3) or three numbers with the 4-digit year first or last. It never guesses (PARITY D-06): a 2-digit year is Ambiguous. It returns a *ParseError when no rule matches, and New's error when the date is invalid. It does not allocate on success; a failed call allocates one *ParseError.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, err := nepdate.ParseLenient("15 Shrawan 2080")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(d)
}
Output:
2080/04/15

func Today

func Today(loc *time.Location) (Date, error)

Today returns today's BS date in loc. A nil loc means Asia/Kathmandu, or the fixed zone NPT (UTC+05:45) when the system has no time zone database; the library doesn't embed one. A server clock in UTC is 5 h 45 min behind Nepal, so pass the zone you mean. It returns ErrOutOfRange if the clock is outside the supported range.

Example
package main

import (
	"fmt"
	"log"
	"time"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	today, err := nepdate.Today(time.FixedZone("NPT", 5*3600+45*60))
	if err != nil {
		log.Fatal(err)
	}
	// The date depends on the clock; the time of the same date does not.
	fmt.Println(today.Time(nil).Format("15:04"))
}
Output:
00:00

func (Date) AddDays

func (d Date) AddDays(n int) (Date, error)

AddDays returns d moved by n days. It returns ErrOutOfRange if the result is outside the supported range or d is the zero Date. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	later, err := d.AddDays(16)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(later)
}
Output:
2081/04/31

func (Date) AddMonths

func (d Date) AddMonths(n int, o Overflow) (Date, error)

AddMonths returns d moved by n months, with o deciding what happens to a day past the end of the target month. It returns ErrOutOfRange if the result is outside the supported range or d is the zero Date. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	later, err := d.AddMonths(4, nepdate.Clamp)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(later)
}
Output:
2081/08/15

func (Date) AddYears

func (d Date) AddYears(n int, o Overflow) (Date, error)

AddYears returns d moved by n years, which is AddMonths(12*n, o). It returns ErrOutOfRange like AddMonths. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2080, nepdate.Falgun, 30)
	later, err := d.AddYears(1, nepdate.Clamp)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(later)
}
Output:
2081/11/29

func (Date) After

func (d Date) After(other Date) bool

After reports whether d is after other. It does not allocate.

func (Date) AppendFormat

func (d Date) AppendFormat(b []byte, pattern string, lang Lang) []byte

AppendFormat is Format appending to b. It does not allocate when b has room.

func (Date) AppendLong

func (d Date) AppendLong(b []byte, opts LongOptions, lang Lang) []byte

AppendLong is Long appending to b. It does not allocate when b has room.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, _ := nepdate.New(2081, nepdate.Shrawan, 15)
	var buf []byte
	buf = d.AppendLong(buf, nepdate.LongOptions{Weekday: true}, nepdate.Nepali)
	fmt.Println(string(buf))
}
Output:
मङ्गलवार, साउन १५, २०८१

func (Date) AppendShort

func (d Date) AppendShort(b []byte, o DateOrder, sep Separator, pad bool, lang Lang) []byte

AppendShort is Short appending to b. It does not allocate when b has room.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	var b []byte
	b = d.AppendShort(b, nepdate.YMD, nepdate.Dot, true, nepdate.English)
	fmt.Println(string(b))
}
Output:
2081.04.15

func (Date) AppendText

func (d Date) AppendText(b []byte) ([]byte, error)

AppendText appends "YYYY-MM-DD" to b (encoding.TextAppender). It does not allocate when b has room, and returns b unchanged with ErrOutOfRange for the zero Date.

func (Date) Before

func (d Date) Before(other Date) bool

Before reports whether d is before other. It does not allocate.

func (Date) Compare

func (d Date) Compare(other Date) int

Compare returns -1 if d is before other, 0 if they are equal and +1 if d is after other. The zero Date sorts before every valid date. It does not allocate.

func (Date) Day

func (d Date) Day() int

Day returns the day of the month, 1..32, or 0 for the zero Date. It does not allocate.

func (Date) DaysUntil

func (d Date) DaysUntil(other Date) int

DaysUntil returns the signed number of days from d to other (PARITY D-07): positive when other is later. It returns 0 if either date is the zero Date. It does not allocate.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	start := nepdate.MustNew(2081, nepdate.Baishakh, 1)
	end := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(start.DaysUntil(end))
}
Output:
108

func (Date) Diff

func (d Date) Diff(other Date) Diff

Diff returns the years, months and days from d to other: the largest whole number of months that, added to the earlier date with Clamp, doesn't pass the later one, then the remaining days. It returns the zero Diff if either date is the zero Date. It does not allocate.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	start := nepdate.MustNew(2081, nepdate.Baishakh, 1)
	end := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	diff := end.Diff(start)
	fmt.Println(diff.Years, diff.Months, diff.Days)
}
Output:
0 3 14

func (Date) FirstOfMonth

func (d Date) FirstOfMonth() Date

FirstOfMonth returns the first day of d's month, or the zero Date for the zero Date. It does not allocate.

func (Date) FiscalYear

func (d Date) FiscalYear() FiscalYear

FiscalYear returns the fiscal year that contains d, or 0 for the zero Date. It does not allocate.

func (Date) Format

func (d Date) Format(pattern string, lang Lang) string

Format returns d formatted by pattern (shared/spec/FORMATTING.md §5) in lang, or "" for the zero Date. The single-letter patterns "", "G", "g" and "d" give "YYYY/MM/DD", "D" the default Long format and "s" "YYYY-MM-DD". Any other pattern is read left to right: runs of y, M and d are the year, month and day; '...' and \x are literal; everything else is copied.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d, _ := nepdate.New(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Format("MMM d, yyyy", nepdate.Nepali))
}
Output:
साउन १५, २०८१

func (Date) Gregorian

func (d Date) Gregorian() (year int, month time.Month, day int)

Gregorian returns the AD date of d, or (0, 0, 0) for the zero Date. It does not allocate.

func (Date) IsZero

func (d Date) IsZero() bool

IsZero reports whether d is the zero Date, which is "no date". It does not allocate.

func (Date) LastOfMonth

func (d Date) LastOfMonth() Date

LastOfMonth returns the last day of d's month, or the zero Date for the zero Date. It does not allocate.

func (Date) Long

func (d Date) Long(opts LongOptions, lang Lang) string

Long returns d as "[Weekday, ]Month DD[, YYYY]" in lang (FORMATTING §4), or "" for the zero Date.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Long(nepdate.LongOptions{Weekday: true}, nepdate.Nepali))
}
Output:
मङ्गलवार, साउन १५, २०८१

func (Date) MarshalText

func (d Date) MarshalText() ([]byte, error)

MarshalText returns d as "YYYY-MM-DD" (PARITY D-11), so encoding/json and other encoders write a Date as a string and accept it as a map key. It returns ErrOutOfRange for the zero Date.

Example
package main

import (
	"encoding/json"
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	payload, err := json.Marshal(struct {
		Date nepdate.Date `json:"date"`
	}{d})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(payload))
}
Output:
{"date":"2081-04-15"}

func (Date) Month

func (d Date) Month() Month

Month returns the BS month, or 0 for the zero Date. It does not allocate.

func (Date) MonthLength

func (d Date) MonthLength() int

MonthLength returns the number of days in d's month, 29..32, or 0 for the zero Date. It does not allocate.

func (Date) Next

func (d Date) Next() (Date, bool)

Next returns the day after d, or (Date{}, false) at Max and for the zero Date. It does not allocate.

func (Date) Prev

func (d Date) Prev() (Date, bool)

Prev returns the day before d, or (Date{}, false) at Min and for the zero Date. It does not allocate.

func (Date) Quarter

func (d Date) Quarter() Quarter

Quarter returns the fiscal quarter that contains d, or 0 for the zero Date. It does not allocate.

func (Date) Short

func (d Date) Short(o DateOrder, sep Separator, pad bool, lang Lang) string

Short returns the three numbers of d in order o, separated by sep, in lang's digits. With pad the year has 4 digits and the month and day 2. It returns "" for the zero Date or an unknown order or separator.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Short(nepdate.DMY, nepdate.Dash, false, nepdate.English))
	fmt.Println(d.Short(nepdate.YMD, nepdate.Slash, true, nepdate.Nepali))
}
Output:
15-4-2081
२०८१/०४/१५

func (Date) String

func (d Date) String() string

String returns d as "YYYY/MM/DD" with ASCII digits (FORMATTING §2), or "" for the zero Date.

func (Date) Time

func (d Date) Time(loc *time.Location) time.Time

Time returns midnight at the start of d in loc, or in UTC when loc is nil. The zero Date returns the zero time.Time.

func (*Date) UnmarshalText

func (d *Date) UnmarshalText(text []byte) error

UnmarshalText sets *d from text in the strict form Parse accepts. On error *d is unchanged. It parses the bytes directly, so it does not allocate on success.

Example
package main

import (
	"encoding/json"
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	var payload struct {
		Date nepdate.Date `json:"date"`
	}
	if err := json.Unmarshal([]byte(`{"date":"2081-04-15"}`), &payload); err != nil {
		log.Fatal(err)
	}
	fmt.Println(payload.Date)
}
Output:
2081/04/15

func (Date) Weekday

func (d Date) Weekday() time.Weekday

Weekday returns the day of the week of d (ALGORITHM §7). The zero Date returns Sunday, the zero value of time.Weekday. It does not allocate.

func (Date) Year

func (d Date) Year() int

Year returns the BS year, 1901..2199, or 0 for the zero Date. It does not allocate.

func (Date) YearDay

func (d Date) YearDay() int

YearDay returns the day of the BS year, 1 for Baishakh 1, or 0 for the zero Date. It does not allocate.

type DateOrder

type DateOrder uint8

DateOrder is the order of the three numbers in Short (shared/spec/FORMATTING.md §3).

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Short(nepdate.DMY, nepdate.Dash, false, nepdate.English))
	fmt.Println(d.Short(nepdate.YMD, nepdate.Dash, true, nepdate.English))
}
Output:
15-4-2081
2081-04-15
const (
	YMD DateOrder = iota
	YDM
	MYD
	MDY
	DYM
	DMY
)

The six orders, in C#'s DateFormats order.

type Diff

type Diff struct {
	Negative bool // the other date is earlier
	// Years, Months and Days are the non-negative magnitudes.
	Years, Months, Days int
	TotalDays           int // the signed day count, the same as DaysUntil
}

Diff is the calendar distance between two dates (ALGORITHM §8a). Years, Months and Days are magnitudes; Negative and TotalDays carry the sign.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	start := nepdate.MustNew(2081, nepdate.Baishakh, 1)
	end := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	diff := start.Diff(end)
	fmt.Println(diff.Years, diff.Months, diff.Days, diff.TotalDays)
	back := end.Diff(start)
	fmt.Println(back.Negative, back.TotalDays)
}
Output:
0 3 14 108
true -108

type FiscalYear

type FiscalYear int

FiscalYear is a Nepal fiscal year, Shrawan 1 to the end of Ashad, named by its starting BS year: FY 2082/83 is FiscalYear(2082) (ALGORITHM §8b, PARITY D-08).

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	f := nepdate.MustNew(2081, nepdate.Shrawan, 15).FiscalYear()
	start, err := f.Start()
	if err != nil {
		log.Fatal(err)
	}
	end, err := f.End()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(f.Label(nepdate.English), start, end)
}
Output:
2081/82 2081/04/01 2082/03/32

func FiscalYearOf

func FiscalYearOf(d Date) FiscalYear

FiscalYearOf returns the fiscal year that contains d, or 0 for the zero Date. It does not allocate.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(nepdate.FiscalYearOf(d).Label(nepdate.English))
}
Output:
2081/82

func (FiscalYear) End

func (f FiscalYear) End() (Date, error)

End returns the last day of Ashad of f+1. It returns ErrOutOfRange if that day is outside the range. It does not allocate.

func (FiscalYear) Label

func (f FiscalYear) Label(lang Lang) string

Label returns the usual name of f, "2082/83" in English or "२०८२/८३" in Nepali. It does not allocate.

func (FiscalYear) QuarterRange

func (f FiscalYear) QuarterRange(q Quarter) (Range, error)

QuarterRange returns the days of quarter q of f. It returns ErrOutOfRange if the quarter is outside the supported range, and also if q is not Q1..Q4: ErrOutOfRange is the error for any argument outside the supported domain. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	f := nepdate.MustNew(2081, nepdate.Shrawan, 15).FiscalYear()
	r, err := f.QuarterRange(nepdate.Q1)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(r.Start(), r.End(), r.Len())
}
Output:
2081/04/01 2081/06/30 93

func (FiscalYear) Range

func (f FiscalYear) Range() (Range, error)

Range returns every day of f. It returns ErrOutOfRange if either end is outside the range. It does not allocate.

func (FiscalYear) Start

func (f FiscalYear) Start() (Date, error)

Start returns Shrawan 1 of f. It returns ErrOutOfRange if that day is outside the range. It does not allocate.

type Lang

type Lang uint8

Lang selects the language of names and digits in formatted output.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	fmt.Println(string(nepdate.English.AppendDigits(nil, 2081, 4)))
	fmt.Println(string(nepdate.Nepali.AppendDigits(nil, 2081, 4)))
}
Output:
2081
२०८१
const (
	English Lang = iota
	Nepali
)

The supported languages. English uses ASCII digits, Nepali uses Devanagari digits.

func (Lang) AppendDigits

func (l Lang) AppendDigits(b []byte, n, minWidth int) []byte

AppendDigits appends n in decimal to b and returns the extended slice. Nepali writes Devanagari digits (U+0966 to U+096F), English writes ASCII digits. The number is zero-padded to at least minWidth digits; minWidth counts digits, not bytes. A negative n gets a leading '-'. It does not allocate when b has room.

type LongOptions

type LongOptions struct {
	Weekday  bool // start with the weekday name
	OmitYear bool // leave out ", <year>"
	NoPad    bool // write the day without a leading zero
}

LongOptions changes Long. The zero value is C#'s default: no weekday, year shown, day padded to 2 digits.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Long(nepdate.LongOptions{}, nepdate.English))
	fmt.Println(d.Long(nepdate.LongOptions{Weekday: true, OmitYear: true}, nepdate.English))
}
Output:
Shrawan 15, 2081
Tuesday, Shrawan 15

type Month

type Month uint8

Month is a Bikram Sambat month, Baishakh = 1 to Chaitra = 12.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	fmt.Println(nepdate.Shrawan.Name(nepdate.English))
	fmt.Println(nepdate.Shrawan.Name(nepdate.Nepali))
	fmt.Println(nepdate.Ashad.ShortName(nepdate.English))
}
Output:
Shrawan
साउन
Asa
const (
	Baishakh Month = 1 + iota
	Jestha
	Ashad
	Shrawan
	Bhadra
	Ashoj
	Kartik
	Mangsir
	Poush
	Magh
	Falgun
	Chaitra
)

The twelve BS months.

func (Month) Name

func (m Month) Name(lang Lang) string

Name returns the month's full name in lang, or "" if m is not 1..12 or lang is unknown. It does not allocate.

func (Month) ShortName

func (m Month) ShortName(lang Lang) string

ShortName returns the three-letter English abbreviation, or the full Nepali name for Nepali, which has no customary abbreviation. Ashad is "Asa" and Ashoj is "Aso" (PARITY D-04). It returns "" if m is not 1..12 or lang is unknown. It does not allocate.

func (Month) String

func (m Month) String() string

String returns the English name of the month, or "" if m is not 1..12.

type Overflow

type Overflow uint8

Overflow says what AddMonths and AddYears do when the day doesn't exist in the target month (ALGORITHM §8).

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	last := nepdate.MustNew(2081, nepdate.Shrawan, 32)
	clamped, err := last.AddMonths(1, nepdate.Clamp)
	if err != nil {
		log.Fatal(err)
	}
	spilled, err := last.AddMonths(1, nepdate.Spill)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(clamped, spilled)
}
Output:
2081/05/31 2081/06/01
const (
	// Clamp moves the day back to the last day of the target month, like C# AddMonths(n).
	Clamp Overflow = iota
	// Spill carries the extra days into the next month, like C# AddMonths(n, awayFromMonthEnd:
	// true). The spec calls this mode Overflow.
	Spill
)

The overflow modes.

type ParseError

type ParseError struct {
	// Input is the text that failed to parse.
	Input string
	// Kind is the syntax rule that failed.
	Kind ParseErrorKind
}

ParseError is returned when the input is not a date in the accepted syntax. A string that parses but names an invalid date returns ErrOutOfRange, ErrInvalidMonth or ErrInvalidDay instead.

Example
package main

import (
	"errors"
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	_, err := nepdate.Parse("2081/04/xx")
	var parseErr *nepdate.ParseError
	if errors.As(err, &parseErr) {
		fmt.Println(parseErr.Input)
		fmt.Println(err)
	}
}
Output:
2081/04/xx
nepdate: cannot parse "2081/04/xx": invalid character

func (*ParseError) Error

func (e *ParseError) Error() string

Error returns a message naming the input and the kind.

type ParseErrorKind

type ParseErrorKind uint8

ParseErrorKind says why the syntax step of Parse or ParseLenient failed (shared/spec/PARSING.md §4).

Example
package main

import (
	"errors"
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	_, err := nepdate.Parse("2081/04/xx")
	var parseErr *nepdate.ParseError
	if errors.As(err, &parseErr) {
		switch parseErr.Kind {
		case nepdate.InvalidCharacter:
			fmt.Println("the date contains a character that is not a digit or a separator")
		case nepdate.WrongGroupCount:
			fmt.Println("the date has the wrong number of parts")
		case nepdate.NumberTooLong:
			fmt.Println("a number in the date is too long")
		case nepdate.Ambiguous:
			fmt.Println("the date is ambiguous")
		case nepdate.Unrecognized:
			fmt.Println("the date is not a recognized form")
		}
	}
}
Output:
the date contains a character that is not a digit or a separator
const (
	InvalidCharacter ParseErrorKind = iota + 1 // a character no rule accepts
	WrongGroupCount                            // not exactly three groups
	NumberTooLong                              // a number with more than 4 digits
	Ambiguous                                  // the input fits more than one reading
	Unrecognized                               // the lenient rules found no date
)

The parse error kinds.

type Quarter

type Quarter uint8

Quarter is a quarter of the fiscal year, Q1 = Shrawan to Ashoj up to Q4 = Baishakh to Ashad.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	fmt.Println(nepdate.Q1.Months())
}
Output:
[Shrawan Bhadra Ashoj]
const (
	Q1 Quarter = 1 + iota
	Q2
	Q3
	Q4
)

The fiscal quarters.

func (Quarter) Months

func (q Quarter) Months() [3]Month

Months returns the three months of q in order, or three zero Months if q is not Q1..Q4. It does not allocate.

type Range

type Range struct {
	// contains filtered or unexported fields
}

Range is an inclusive span of dates, start <= end. The zero Range is empty. It has no set operations (PARITY D-09): range over Days and filter instead.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	start := nepdate.MustNew(2081, nepdate.Shrawan, 1)
	end := nepdate.MustNew(2081, nepdate.Shrawan, 3)
	r, ok := nepdate.NewRange(start, end)
	if !ok {
		log.Fatal("start is after end")
	}
	fmt.Println(r.Start(), r.End(), r.Len(), r.Contains(end))
}
Output:
2081/04/01 2081/04/03 3 true

func MonthRange

func MonthRange(year int, month Month) (Range, error)

MonthRange returns every day of the given BS month. It returns New's errors for an invalid year or month. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	r, err := nepdate.MonthRange(2081, nepdate.Shrawan)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(r.Start(), r.End(), r.Len())
}
Output:
2081/04/01 2081/04/32 32

func NewRange

func NewRange(start, end Date) (Range, bool)

NewRange returns the range start..end. It returns false if start is after end or either date is the zero Date. It does not allocate.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	start := nepdate.MustNew(2081, nepdate.Shrawan, 1)
	end := nepdate.MustNew(2081, nepdate.Shrawan, 3)
	r, ok := nepdate.NewRange(start, end)
	fmt.Println(ok, r.Len())
}
Output:
true 3

func YearRange

func YearRange(year int) (Range, error)

YearRange returns every day of the BS year, Baishakh 1 to the last day of Chaitra. It returns ErrOutOfRange for a year outside 1901..2199. It does not allocate.

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	r, err := nepdate.YearRange(2081)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(r.Start(), r.End(), r.Len())
}
Output:
2081/01/01 2081/12/31 366

func (Range) Contains

func (r Range) Contains(d Date) bool

Contains reports whether d is in r. The zero Date is in no range. It does not allocate.

func (Range) Days

func (r Range) Days() iter.Seq[Date]

Days returns an iterator over the days of r in order. It does not allocate when ranged over directly (ADR-0002 §6).

Example
package main

import (
	"fmt"
	"log"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	start := nepdate.MustNew(2081, nepdate.Shrawan, 1)
	end := nepdate.MustNew(2081, nepdate.Shrawan, 3)
	r, ok := nepdate.NewRange(start, end)
	if !ok {
		log.Fatal("start is after end")
	}
	for d := range r.Days() {
		fmt.Println(d)
	}
}
Output:
2081/04/01
2081/04/02
2081/04/03

func (Range) End

func (r Range) End() Date

End returns the last day of r, or the zero Date for the zero Range. It does not allocate.

func (Range) Len

func (r Range) Len() int

Len returns the number of days in r, counting both ends, or 0 for the zero Range. It does not allocate.

func (Range) Start

func (r Range) Start() Date

Start returns the first day of r, or the zero Date for the zero Range. It does not allocate.

type Separator

type Separator uint8

Separator is the character between the numbers in Short.

Example
package main

import (
	"fmt"

	nepdate "github.com/sanamhub/nepdate-go"
)

func main() {
	d := nepdate.MustNew(2081, nepdate.Shrawan, 15)
	fmt.Println(d.Short(nepdate.YMD, nepdate.Dot, true, nepdate.English))
	fmt.Println(d.Short(nepdate.YMD, nepdate.Space, true, nepdate.English))
}
Output:
2081.04.15
2081 04 15
const (
	Slash Separator = iota
	Backslash
	Dot
	Underscore
	Dash
	Space
)

The separators: '/', '\', '.', '_', '-' and ' '.

Directories

Path Synopsis
internal
ci command
Command ci runs every quality gate of ADR-0004 in order and stops at the first failure.
Command ci runs every quality gate of ADR-0004 in order and stops at the first failure.
coreonly command
Command coreonly converts one date using only package nepdate.
Command coreonly converts one date using only package nepdate.
gen command
Command gen writes the generated tables of package nepdate from shared/data/.
Command gen writes the generated tables of package nepdate from shared/data/.
withpatro command
Command withpatro prints the English events of BS 2081-04-15.
Command withpatro prints the English events of BS 2081-04-15.
Package patro is the Nepali almanac (पात्रो) for package nepdate: the tithi (lunar day), the public holiday flag and the events of a BS date.
Package patro is the Nepali almanac (पात्रो) for package nepdate: the tithi (lunar day), the public holiday flag and the events of a BS date.
tools
api-check command
Command api-check guards the exported API of nepdate and patro.
Command api-check guards the exported API of nepdate and patro.
consumer-check command
Command consumer-check builds a throwaway module outside this repository that imports github.com/sanamhub/nepdate-go through a replace directive to this checkout.
Command consumer-check builds a throwaway module outside this repository that imports github.com/sanamhub/nepdate-go through a replace directive to this checkout.
data-status command
Command data-status reports how long the compiled patro data lasts.
Command data-status reports how long the compiled patro data lasts.
fuzz-check command
Command fuzz-check runs every fuzz target in the module for a fixed budget.
Command fuzz-check runs every fuzz target in the module for a fixed budget.
mutation-check command
Command mutation-check runs Gremlins on the core package or patro and enforces the mutation gate.
Command mutation-check runs Gremlins on the core package or patro and enforces the mutation gate.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL