2
\$\begingroup\$

I've been battling ChatGPT for hours now and can't get satisfied with this simple algorithm in TypeScript. These two (hopefully correct) TypeScript+ReactNative solutions should move the timestamp forward to the following Monday 10:01 AM.

    function computeUpcomingNotificationTimestamp(
        currentTimestamp: number = Date.now(),
        day: number = 1,
        hours: number = 10,
        minutes: number = 1
    ): number {
        const currentTimeInMilliseconds: number =
            date.getHours() * 60 * 60 * 1000 // Hours to milliseconds
           +date.getMinutes() * 60 * 1000    // Minutes to milliseconds
           +date.getSeconds() * 1000         // Seconds to milliseconds
           +date.getMilliseconds();          // Milliseconds

        const timeOfNotification: number =
            hours * 60 * 60 * 1000 // Hours to milliseconds
           +minutes * 60 * 1000;   // Minutes to milliseconds

        if (date.getDay() === day) {
            if (currentTimeInMilliseconds >= timeOfNotification) {
                date.setDate(date.getDate() + 7);
            }
        } else {
            while (date.getDay() !== day) {
                date.setDate(date.getDate() + 1);
            }
        }

        date.setHours(hours, minutes, 0, 0);

        return date.getTime();
    };
    
    computeUpcomingNotificationTimestamp();

Here is another (painfully slow, but correct) solution.

function crazyInefficient(
    currentTimestamp: number = Date.now(), 
    day: number = 1, 
    hours: number = 10, 
    minutes: number = 1
): number {
    const date: Date = new Date(currentTimestamp);        
    do {
        date.setTime(date.getTime() + 1);
    } while (date.getDay() !== day || date.getHours() !== hours || date.getMinutes() !== minutes || date.getSeconds() !== 0 || date.getMilliseconds() !== 0);

    return date.getTime();
}
    
crazyInefficient();

What I wish to achieve is a solution that has these properties.

Comprehensible for humans

  • it must be readily apparent, so transparent a CHILD should grasp it instantly and SWEAR it is correct. If it were a suspect domicile and you were a cop who have 10 seconds to persuade the judge to grant you a search warrant, you MUST be able to SWAY HIM!
  • No hacks, no bit-shifts, no Quake 3 arena stuff, nothing too clever
  • just something concisely elegant and vivid

Other important features

  • correct
  • good programming practises (no spaghetti code, complicated conditions, nested if-else)
  • functional, if it serves the purpose
  • pragmatic (if there is a library, just use it please)

This is the closest I got, but there must be a better way. I would be beholden to you, the community.

Here are the unit tests in Jest.

// computeUpcomingNotificationTimestamp.test.ts
import { computeUpcomingNotificationTimestamp } from './your-module';

describe('computeUpcomingNotificationTimestamp', () => {
  // Existing test case...

  it('Sunday 12 AM should return next Monday at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-12T00:00:00Z').getTime(); // Sunday
    const expectedTimestamp = new Date('2023-03-13T10:01:00Z').getTime(); // Next Monday
    expect(computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1)).toBe(expectedTimestamp);
  });

  it('Monday 9 AM should return same day at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-13T09:00:00Z').getTime(); // Monday 9 AM
    const expectedTimestamp = new Date('2023-03-13T10:01:00Z').getTime(); // Same day
    expect(computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1)).toBe(expectedTimestamp);
  });

  it('Monday 10:00:59.999 AM should return same day at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-13T10:00:59.999Z').getTime(); // Just before 10:01 AM
    const expectedTimestamp = new Date('2023-03-13T10:01:00Z').getTime(); // Same day
    expect(computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1)).toBe(expectedTimestamp);
  });

  it('Monday 10:01:00.000 AM should return next Monday at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-13T10:01:00.000Z').getTime();
    const expectedTimestamp = new Date('2023-03-20T10:01:00.000Z').getTime();
    const result = computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1);
    expect(result).toBe(expectedTimestamp);
  });

  it('Monday 10:01:00.001 AM should return next Monday at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-13T10:01:00.001Z').getTime(); // Just after 10:01 AM
    const expectedTimestamp = new Date('2023-03-20T10:01:00Z').getTime(); // Next Monday
    expect(computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1)).toBe(expectedTimestamp);
  });

  it('Monday 10:01:01.000 AM should return next Monday at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-13T10:01:01.000Z').getTime(); // One second after 10:01 AM
    const expectedTimestamp = new Date('2023-03-20T10:01:00Z').getTime(); // Next Monday
    expect(computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1)).toBe(expectedTimestamp);
  });

  it('Monday 10:01:59.000 AM should return next Monday at 10:01 AM', () => {
    const testTimestamp = new Date('2023-03-13T10:01:59.000Z').getTime(); // One minute before 10:02 AM
    const expectedTimestamp = new Date('2023-03-20T10:01:00Z').getTime(); // Next Monday
    expect(computeUpcomingNotificationTimestamp(testTimestamp, 1, 10, 1)).toBe(expectedTimestamp);
  });

  // ...any additional test cases
});
\$\endgroup\$
3
  • \$\begingroup\$ User called @Xiduzo has advised me to use libraries like day.js.org, github.com/moment/luxon or prefferably date-fns.org. Do you think that would be useful? \$\endgroup\$
    – Slazer
    Nov 28, 2023 at 15:50
  • \$\begingroup\$ ChatGPT might not be the right tool to solve programming problems. It is just a large language model-based chatbot that computes the most likely answer to your question. Note that it doesn't know anything about programming, and just regurgitates what it has seen before. It is very good at that because of the current speed of computers, and vast resources available, but it can also easily hallucinate something incredibly stupid. Never rely on a robot to do your work, use your own brain. At best it can point you in a certain direction. \$\endgroup\$ Nov 30, 2023 at 21:00
  • \$\begingroup\$ Please note we have a fairly strict policy on content generated by generative artificial intelligence tools. \$\endgroup\$
    – Mast
    Feb 25 at 17:01

1 Answer 1

1
\$\begingroup\$

Yikes! Use a datetime library already, that's what they're there for, it's a solved problem.


test suite

I didn't see any automated unit tests in this submission. If you want to convince me of correctness, show me that Green bar!


global variable

You're tightly coupled to a global variable: the system clock. (UPDATE: The first function never refers to currentTimestamp, and I interpreted date as accessing current wall-clock time. Possibly OP had a copy-n-paste error, since second function calls new Date(currentTimestamp) and the first function probably wants to include a similar line.) Ok, now I'm beginning to see why there's no unit tests. You designed a Public API which makes testing hard.

Much better to accept a time parameter, and default it to .now() if a lazy caller left it null.


algorithm

I don't have a favorite library. But any of them will be able to parse string --> time, and tell you which day of the week a given time is.

Define MILLIS_PER_DAY = 86400 * 1000 and MONDAY = 1. (Different libraries have different conventions on how to number the days of the week, so read the docs.)

Assign time by formatting currentTimestamp as a string, with the H:M:S portion unconditionally set to "10:01:00". (Or set integer fields, whichever you find more convenient.)

While time < currentTimestamp and time.day() != MONDAY: time += MILLIS_PER_DAY

So we set time to ten o'clock today, which is either a little in the future or the past, and then we fast-forward one day at a time looking for a future Monday deadline. At most we troll through the loop seven times. (The spec said nothing about skipping bank holidays.) We could use mod 7 math to skip ahead by exactly the appropriate number of days, but it might be less obvious.

There is an edge case that is perhaps not fully determined by the spec you mentioned. December 4th will be a Monday. Be sure to include both 9am and 11am on the 4th in your test suite, and ask yourself if you're happy with both of the results.

\$\endgroup\$
3
  • \$\begingroup\$ I have added the unit tests, as you requested. \$\endgroup\$
    – Slazer
    Nov 28, 2023 at 19:04
  • \$\begingroup\$ I am not sure your solution works for the cutoff 10:01:00:000 the way it is defined in my unit tests. Also I didn't understand the paragraph "global variable" at all, sorry :D. No holidays are considered. Either way, I am worried the computed value wont be in sync with my triggered notification anyway :/ but that's for another discussion. \$\endgroup\$
    – Slazer
    Nov 28, 2023 at 19:18
  • \$\begingroup\$ I'm really sorry, but I don't get your algorithm. Coud you please give me the TypeScript version? The currentTimestamp is our starting point, which we try to forward to following Monday 10:01:00:000 AM. It is a Unix timestamp, the Epoch, i.e. the number of seconds that have elapsed since January 1, 1970. \$\endgroup\$
    – Slazer
    Nov 29, 2023 at 3:38

Not the answer you're looking for? Browse other questions tagged or ask your own question.