Skip to main content
Fraud patterns are often time-dependent. Legitimate transactions tend to follow predictable temporal patterns — business hours, weekdays, regular pay cycles. When a transaction breaks these patterns, it’s a signal worth investigating. This guide teaches you how to build rules that are aware of when a transaction happens.

Why Time Matters

Consider these scenarios:
  • A corporate account that normally processes payroll on weekday mornings suddenly initiates a wire transfer at 3 AM on a Saturday.
  • A consumer account that’s been inactive for months makes a large purchase at 2 AM.
  • A series of rapid transactions occur during a national holiday when the account holder is unlikely to be actively spending.
None of these transactions are inherently suspicious based on amount or destination alone. It’s the timing that makes them unusual. Time functions give you the vocabulary to express these patterns.

hour_of_day()

Extracts the hour component from a transaction’s timestamp. Signature: hour_of_day(<timestamp_field>) Return Value: An integer from 0 to 23 representing the hour in UTC.
  • 0 = midnight (12:00 AM)
  • 12 = noon (12:00 PM)
  • 23 = 11:00 PM

Example: Flagging Transactions During Unusual Hours

What this detects: Any transaction over $1,000 that occurs between 1:00 AM and 4:59 AM UTC. This is a common window for fraudulent activity — compromised accounts are often exploited when the legitimate owner is asleep. Why three conditions? We use two hour_of_day() checks to define a range (>= 1 AND < 5), and combine them with an amount threshold to avoid flagging every small late-night coffee purchase.

Example: Late Night OR Early Morning

If you want to flag transactions that happen late at night or very early in the morning (spanning midnight), you need to handle the boundary carefully:
This fires for transactions at 11 PM, midnight, 1 AM, 2 AM, or 3 AM.
Warning: Remember the precedence pitfall. If you add an and amount > 1000 after the or clause, the grouping becomes (hour >= 23 OR hour <= 3) AND amount > 1000. If your intent is different, consider splitting into two rules.

Combining with Amount for High-Risk Detection

By putting the cheap amount > 5000 check first, the hour_of_day() function only runs on transactions that pass the amount threshold — an example of the gate-and-probe pattern.

day_of_week()

Extracts the day of the week from a transaction’s timestamp. Signature: day_of_week(<timestamp_field>) Return Value: An integer from 0 to 6:

Example: Weekend Transaction Monitoring

What this detects: Transactions on Sunday (0) or Saturday (6) that exceed $5,000. Business accounts typically don’t process payments on weekends, so weekend activity can indicate unauthorized access.

Special Feature: String Day Names with in

The day_of_week() function also supports string comparisons when used with the in operator. You can use day names instead of numbers:
This is equivalent to checking for 0 or 6, but more readable.

Example: Business Hours Only


Other Time Functions

FinWatch provides a complete set of temporal extraction functions. While hour_of_day() and day_of_week() are the most commonly used, the others are valuable for specific scenarios.

day_of_month()

Signature: day_of_month(<timestamp_field>) Return Value: An integer from 1 to 31. Use Case: Detecting activity on specific calendar days. For example, payroll fraud often targets specific days (1st, 15th, last day of month).

day_of_year()

Signature: day_of_year(<timestamp_field>) Return Value: An integer from 1 to 366. Use Case: Identifying transactions on specific dates, such as holidays or known fraud campaign windows.
Note: Day 359 is December 25th in a non-leap year. For production rules, consider using month_of_year() and day_of_month() together for clarity.

month_of_year()

Signature: month_of_year(<timestamp_field>) Return Value: An integer from 1 (January) to 12 (December). Use Case: Seasonal fraud patterns. Fraud attempts often spike during holiday shopping seasons (November, December) and tax filing periods (January through April).

week_of_year()

Signature: week_of_year(<timestamp_field>) Return Value: An integer from 1 to 53 (ISO week number). Use Case: Weekly pattern analysis or identifying specific weeks with known elevated risk (e.g., Black Friday week, tax deadline week).

year()

Signature: year(<timestamp_field>) Return Value: The full year as an integer (e.g., 2026). Use Case: Filtering out stale or future-dated transactions. A transaction with year(timestamp) < 2020 is almost certainly a data error.

Combining Time with Other Conditions

The real power of time functions emerges when you combine them with other condition types — simple comparisons, aggregates, and metadata checks.

Multi-Factor Time-Based Detection

This rule layers four conditions:
  1. Amount: Over $10,000 (eliminates low-value noise).
  2. Time: Between 1 AM and 5 AM (unusual hours).
  3. Time: Same check, upper bound.
  4. Account age: Less than 30 days (new account).
Each condition alone might not be concerning. Together, they paint a high-risk picture: a brand-new account making large transfers in the middle of the night.

Time + Aggregates

This combines a time check (after 10 PM) with a velocity check (more than 5 transactions from the same source in the last hour). During daytime, 5 transactions per hour might be normal. At night, it’s suspicious.

Time Zone Considerations

All time functions in FinWatch operate on the transaction’s timestamp field and return values in UTC. This is an important detail for global fintechs operating across multiple time zones.

What This Means in Practice

If your users are in West Africa (UTC+1), a transaction at “2 AM local time” would have a UTC timestamp of 1 AM. A rule checking hour_of_day(timestamp) >= 2 would not match this transaction.

Recommendations

  1. Store timestamps in UTC. This is best practice regardless of FinWatch. All API payloads should use RFC 3339 UTC timestamps (e.g., 2026-04-18T14:30:00Z).
  2. Design rules with UTC offsets in mind. If your users are primarily in UTC+1, and you want to flag “late night” activity (midnight to 5 AM local), your UTC range would be 11 PM to 4 AM:
  1. Use metadata for timezone-aware rules. If you need timezone-specific logic, include the user’s timezone or local hour in the transaction metadata:
Then your rule can check metadata.local_hour directly:
This approach offloads the timezone conversion to your application, where it belongs.

Next Steps