code: private static long periodEnd(long now, 
                                  long period, 
                                  LocalDateTime cal)
    {
      if (period < 0)
        return Long.MAX_VALUE;
      else if (period == 0)
        return now;
  
      if (period < 30 * DAY) {
        //cal.setGMTTime(now);
  
        long localTime = cal.toEpochSecond(ZoneOffset.UTC) * 1000;
  
        localTime = localTime + (period - (localTime + 4 * DAY) % period);
  
        //cal.setLocalTime(localTime);
  
        //return cal.getGMTTime();
        return cal.toEpochSecond(ZoneOffset.UTC) * 1000;
      }
  
      if (period % (30 * DAY) == 0) {
        int months = (int) (period / (30 * DAY));
  
        //cal.setGMTTime(now);
        long year = cal.getYear();
        int month = cal.getMonthValue();
  
        //cal.setLocalTime(0);
        
        //cal.setDate(year, month + months, 1);
        cal.withMonth(month + months);
        cal.withDayOfMonth(1);
  
        return cal.toEpochSecond(ZoneOffset.UTC) * 1000;
      }
  
      if (period % (365 * DAY) == 0) {
        long years = (period / (365 * DAY));
  
        //cal.setGMTTime(now);
        long year = cal.getYear();
  
        //cal.setLocalTime(0);
  
        long newYear = year + (years - year % years);
        
        cal.withYear((int) newYear);
        cal.withMonth(1);
        cal.withDayOfMonth(1);
  
        return cal.toEpochSecond(ZoneOffset.UTC) * 1000;
      }
  
      //cal.setGMTTime(now);
  
      //long localTime = cal.getLocalTime();
  
      //localTime = localTime + (period - (localTime + 4 * DAY) % period);
  
      //cal.setLocalTime(localTime);
  
      //return cal.getGMTTime();
      return cal.toEpochSecond(ZoneOffset.UTC) * 1000;
    }
docs: Calculates the next period end.  The calculation is in local time.
  
  @param now the current time in GMT ms since the epoch
  
  @return the time of the next period in GMT ms since the epoch