func (p *ProfileId) IsValid(at time.Time) bool {
  return !p.FirstSeenAt.After(at) && p.ValidUntil.After(at)
}
evaluates whether the profile is still valid at the given time
package entity
import (
  "encoding/json"
  "io"
  "time"
  "github.com/google/uuid"
)
type ProfileId struct {
  Id          uuid.UUID
  Name        string
  FirstSeenAt time.Time
  LastSeenAt  time.Time
  ValidUntil  time.Time
}
type restProfileId struct {
  Id   string `json:"id"`
  Name string `json:"name"`
}
type serializableProfileId struct {
  restProfileId
  FirstSeenAt int64 `json:"firstSeenAt"`
  LastSeenAt  int64 `json:"lastSeenAt"`
  ValidUntil  int64 `json:"validUntil"`
}
func (p *ProfileId) Serialize() ([]byte, error) {
  enc := serializableProfileId{
    restProfileId: restProfileId{
      Id:   p.Id.String(),
      Name: p.Name,
    },
    FirstSeenAt: p.FirstSeenAt.Unix(),
    LastSeenAt:  p.LastSeenAt.Unix(),
    ValidUntil:  p.ValidUntil.Unix(),
  }
  return json.Marshal(&enc)
}
func SerializeProfileIdArray(profileIds []*ProfileId) ([]byte, error) {
  enc := make([]serializableProfileId, len(profileIds))
  for i, profileId := range profileIds {
    enc[i] = serializableProfileId{
      restProfileId: restProfileId{
        Id:   profileId.Id.String(),
        Name: profileId.Name,
      },
      FirstSeenAt: profileId.FirstSeenAt.Unix(),
      LastSeenAt:  profileId.LastSeenAt.Unix(),
      ValidUntil:  profileId.ValidUntil.Unix(),
    }
  }
  return json.Marshal(&enc)
}
func (p *ProfileId) Deserialize(enc []byte) error {
  parsed := serializableProfileId{}
  err := json.Unmarshal(enc, &parsed)
  if err != nil {
    return err
  }
  id, err := uuid.Parse(parsed.Id)
  if err != nil {
    return err
  }
  p.Id = id
  p.Name = parsed.Name
  p.FirstSeenAt = time.Unix(parsed.FirstSeenAt, 0)
  p.LastSeenAt = time.Unix(parsed.LastSeenAt, 0)
  p.ValidUntil = time.Unix(parsed.ValidUntil, 0)
  return nil
}
func DeserializeProfileIdArray(enc []byte) ([]*ProfileId, error) {
  parsed := make([]serializableProfileId, 0)
  err := json.Unmarshal(enc, &parsed)
  if err != nil {
    return nil, err
  }
  res := make([]*ProfileId, len(parsed))
  for i, profileId := range parsed {
    id, err := uuid.Parse(profileId.Id)
    if err != nil {
      return nil, err
    }
    res[i] = &ProfileId{
      Id:          id,
      Name:        profileId.Name,
      FirstSeenAt: time.Unix(profileId.FirstSeenAt, 0),
      LastSeenAt:  time.Unix(profileId.LastSeenAt, 0),
      ValidUntil:  time.Unix(profileId.ValidUntil, 0),
    }
  }
  return res, nil
}
func (p *ProfileId) Read(reader io.Reader, at time.Time) error {
  parsed := restProfileId{}
  err := json.NewDecoder(reader).Decode(&parsed)
  if err != nil {
    return err
  }
  id, err := ParseId(parsed.Id)
  if err != nil {
    return err
  }
  p.Id = id
  p.Name = parsed.Name
  p.FirstSeenAt = at
  p.LastSeenAt = at
  p.ValidUntil = CalculateNameGracePeriodEnd(at)
  return nil
}
func ReadProfileIdArray(reader io.Reader) ([]*ProfileId, error) {
  parsed := make([]restProfileId, 0)
  err := json.NewDecoder(reader).Decode(&parsed)
  if err != nil {
    return nil, err
  }
  at := time.Now()
  res := make([]*ProfileId, len(parsed))
  for i, profileId := range parsed {
    id, err := ParseId(profileId.Id)
    if err != nil {
      return nil, err
    }
    res[i] = &ProfileId{
      Id:          id,
      Name:        profileId.Name,
      FirstSeenAt: at,
      LastSeenAt:  at,
      ValidUntil:  CalculateNameGracePeriodEnd(at),
    }
  }
  return res, nil
}
func (p *ProfileId) UpdateDiscovery(at time.Time) {
  p.FirstSeenAt = at
  p.LastSeenAt = at
  p.ValidUntil = CalculateNameGracePeriodEnd(at)
}
func (p *ProfileId) UpdateExpiration(seen time.Time) {
  if p.LastSeenAt.After(seen) {
    return  
  }
  p.LastSeenAt = seen
  p.ValidUntil = CalculateNameGracePeriodEnd(seen)
}