Skip to content
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
127 lines (108 sloc) 3.79 KB
package gedcom
import (
// Year is an approximation for the duration of a year.
// This should not be used in calculations that require more than month-level
// precision.
// A year is approximated at 365.25 to take into account leap years.
const Year = time.Duration(float64(time.Hour) * 24 * 365.25)
// Age represents an age of an individual at a point in time.
// An Age is often paired with another Age to allow a range of time. For example
// an event could be an absolute like a christening, or it could represent a
// range such as the start and end age during a residence that spans multiple
// years.
// You should avoid initializing the struct directly, and instead use the most
// appropriate constructor.
type Age struct {
// Age is the duration of time from the point where the birth was
// determined.
// The age may be an estimation, see IsEstimate. The age might also be
// greater than the maximum living age of the individual, see IsAfterDeath.
Age time.Duration
// IsEstimate will be true when there was no birth event or the birth event
// is a range (like "Between 1943 to 1947").
IsEstimate bool
// IsKnown will be true if the age can be determined (either as exact or an
// estimation). The age cannot be determined if no estimated birth date is
// found or an event does not contain a usable date.
// When IsKnown is false you should not use the value of Age.
IsKnown bool
// See the AgeConstraint constants for a full explanation.
Constraint AgeConstraint
// NewUnknownAge returns a value that represents an age that is not known.
func NewUnknownAge() Age {
return Age{}
// NewAge will initialise a new known exact or estimate age age with the
// provided attributes.
func NewAge(age time.Duration, isEstimate bool, constraint AgeConstraint) Age {
return Age{
Age: age,
IsKnown: true,
IsEstimate: isEstimate,
Constraint: constraint,
// NewAgeWithYears creates an age by using the number of years.
// This is not precise as a year is averaged out at 365.25 days (see Year
// constant) but is useful when only whole years matter.
func NewAgeWithYears(years float64, isEstimate bool, constraint AgeConstraint) Age {
year := float64(Year)
age := time.Duration(years * year)
return NewAge(age, isEstimate, constraint)
// IsAfter is true if the right age is after (greater than) the left age. If
// both ages are equal this will return false.
func (age Age) IsAfter(age2 Age) bool {
return age.Age > age2.Age
// Years returns the approximate amount of years.
// The value is approximate because a year is both a variable amount of time and
// has to be combined with a point in time to be practical.
// Years can be used when 1 month resolution is enough. However, it's not
// recommended to use this for calculations. Instead use the Age value.
func (age Age) Years() float64 {
// ghost:ignore
return float64(age.Age) / float64(Year)
// String returns an age in one of the following forms:
// unknown -- if IsKnown is false
// 20y -- living age is very close to the whole year
// 20y 5m -- living age with 5 months
// ~ 25y -- if IsEstimated is true
// ~ 22y 11m -- same as above
// String will not consider the age constraint.
// A special case is 0. When the age duration is zero (or less than half of one
// month) the estimate marker ("~") will not be shown because this would not
// make sense.
func (age Age) String() string {
if !age.IsKnown {
return "unknown"
years := int(age.Years())
// ghost:ignore
months := int((age.Years() - float64(years)) * 12)
estimateSign := ""
if age.IsEstimate && years+months > 0 {
estimateSign = "~ "
if months == 0 {
return fmt.Sprintf("%s%dy", estimateSign, years)
return fmt.Sprintf("%s%dy %dm", estimateSign, years, months)
You can’t perform that action at this time.