【问题标题】:How do you generate a random date in objective-c?你如何在objective-c中生成一个随机日期?
【发布时间】:2012-04-22 23:06:35
【问题描述】:

我想在两个日期之间生成一个随机日期,例如从今天到 60 天之间的随机日期。我该怎么做?

更新

使用答案中的信息,我想出了这个我经常使用的方法:

// Generate a random date sometime between now and n days before day.
// Also, generate a random time to go with the day while we are at it.
- (NSDate *) generateRandomDateWithinDaysBeforeToday:(NSInteger)days
{
    int r1 = arc4random_uniform(days);
    int r2 = arc4random_uniform(23);
    int r3 = arc4random_uniform(59);

    NSDate *today = [NSDate new];
    NSCalendar *gregorian = 
             [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];

    NSDateComponents *offsetComponents = [NSDateComponents new];
    [offsetComponents setDay:(r1*-1)];
    [offsetComponents setHour:r2];
    [offsetComponents setMinute:r3];

    NSDate *rndDate1 = [gregorian dateByAddingComponents:offsetComponents 
                                                  toDate:today options:0];

    return rndDate1;
}

【问题讨论】:

标签: ios objective-c cocoa cocoa-touch


【解决方案1】:

获取一个随机数并将其用作时间间隔,然后将其添加到开始日期。例如

NSTimeInterval timeBetweenDates = [endDate timeIntervalSinceDate:startDate];
NSTimeInterval randomInterval = ((NSTimeInterval)arc4random() / ARC4RANDOM_MAX) * timeBetweenDates;

NSDate *randomDate = [startDate dateByAddingTimeInterval:randomInterval];

【讨论】:

  • 如果您收到有关 ARC4RANDOM_MAX 的错误,请将其替换为 0x100000000 或使用 #define ARC4RANDOM_MAX 0x100000000
  • 顺便说一句,我认为这应该是公认的答案,因为它比公认的答案解决了更多随机日期的用例。
【解决方案2】:
  1. 生成一个介于 1 到 60 之间的随机数

    int r = arc4random_uniform(60) + 1;
    
    // Usage : arc4random_uniform(hi - lo + 1) + lo
    
  2. 获取当前日期

    [NSDate date];
    
  3. 使用NSDateComponentsdays 组件中减去随机数并生成新日期。

【讨论】:

  • 虽然在这里可能不是什么大问题,但使用 % 几乎总是会偏向随机数。你想要的函数是 arc4random_uniform()。
  • arc4random_uniform(upper_bound) 只返回一个大于或等于 0 且小于 upper_bound 的整数,这样分布是均匀的。也就是说,该范围内的所有值的可能性均等。
  • @RobNapier : 谢谢你启发我:)
  • 很好的信息。谢谢!我不知道如何解决这个问题。现在,我不仅有了一个好的解决方案,而且还学到了一些关于随机数生成的知识! arc4random() 的非均匀分布(在创建 BOOL 时尤其糟糕)一直困扰着我。
【解决方案3】:

这里的框架在生成随机日期方面做得很好。但在斯威夫特: https://github.com/thellimist/SwiftRandom/blob/master/SwiftRandom/Randoms.swift

public extension NSDate {
    /// SwiftRandom extension
    public static func randomWithinDaysBeforeToday(days: Int) -> NSDate {
        let today = NSDate()

        guard let gregorian = NSCalendar(calendarIdentifier: NSCalendarIdentifierGregorian) else {
            print("no calendar \"NSCalendarIdentifierGregorian\" found")
            return today
        }

        let r1 = arc4random_uniform(UInt32(days))
        let r2 = arc4random_uniform(UInt32(23))
        let r3 = arc4random_uniform(UInt32(23))
        let r4 = arc4random_uniform(UInt32(23))

        let offsetComponents = NSDateComponents()
        offsetComponents.day = Int(r1) * -1
        offsetComponents.hour = Int(r2)
        offsetComponents.minute = Int(r3)
        offsetComponents.second = Int(r4)

        guard let rndDate1 = gregorian.dateByAddingComponents(offsetComponents, toDate: today, options: []) else {
            print("randoming failed")
            return today
        }
        return rndDate1
    }

    /// SwiftRandom extension
    public static func random() -> NSDate {
        let randomTime = NSTimeInterval(arc4random_uniform(UInt32.max))
        return NSDate(timeIntervalSince1970: randomTime)
    }

}

【讨论】:

  • 不错的扩展! r3 和 r4 随机数不应该随机到 59 吗?
  • 嗯,是的:D 随时在 github 上发送拉取请求
  • 好的,拉取请求已发送。顺便说一句,SwiftRandom 非常有用,感谢您的建议!你是作者吗?
  • 链接断开! @Esqarrouth
【解决方案4】:

这是一个 Swift 4.x 扩展,允许您指定天数,然后它将用于在当前日期之前或之后查找随机的Date。 p>

extension Date {
    static func randomDate(range: Int) -> Date {
        // Get the interval for the current date
        let interval =  Date().timeIntervalSince1970
        // There are 86,400 milliseconds in a day (ignoring leap dates)
        // Multiply the 86,400 milliseconds against the valid range of days
        let intervalRange = Double(86_400 * range)
        // Select a random point within the interval range
        let random = Double(arc4random_uniform(UInt32(intervalRange)) + 1)
        // Since this can either be in the past or future, we shift the range
        // so that the halfway point is the present
        let newInterval = interval + (random - (intervalRange / 2.0))
        // Initialize a date value with our newly created interval
        return Date(timeIntervalSince1970: newInterval)
    }
}

你这样称呼它:

Date.randomDate(range: 500) // Any date that is +/- 500 days from the current date

运行 10 次会产生:

2019-03-15 01:45:52 +0000
2018-12-20 02:09:51 +0000
2018-06-28 10:28:31 +0000
2018-08-02 08:13:01 +0000
2019-01-25 07:04:18 +0000
2018-08-30 22:37:52 +0000
2018-10-05 19:38:22 +0000
2018-11-30 04:51:18 +0000
2019-03-24 07:27:39 +0000

【讨论】:

    【解决方案5】:

    使用秒数。伪代码:

    1 Generate a random integer between 0 and (60 * 60 * 24 * 60)
    2 Get the unixtime in seconds for the current time
    3 Add your random integer
    4 Convert this integer back to a date
    

    【讨论】:

    • 由于夏令时的开始和停止,天可以长于或短于 24 小时。
    • 啊,是的,没错。此方法将在 60 天 +/- 一个小时内生成一个随机日期,这在大多数情况下是可以接受的。
    【解决方案6】:

    Swift 3.x +

    public extension Date {
        /// SwiftRandom extension
        public static func randomWithinDaysBeforeToday(days: Int) -> Date {
            let today = Date()
            let gregorian = Calendar(identifier: .gregorian)
    
            let r1 = arc4random_uniform(UInt32(days))
            let r2 = arc4random_uniform(UInt32(23))
            let r3 = arc4random_uniform(UInt32(23))
            let r4 = arc4random_uniform(UInt32(23))
    
            let offsetComponents = NSDateComponents()
            offsetComponents.day = Int(r1) * -1
            offsetComponents.hour = Int(r2)
            offsetComponents.minute = Int(r3)
            offsetComponents.second = Int(r4)
    
            let rndDate1 = gregorian.date(byAdding: offsetComponents as DateComponents, to: today)
            return rndDate1!
        }
    
        /// SwiftRandom extension
        public static func random() -> Date {
            let randomTime = TimeInterval(arc4random_uniform(UInt32.max))
            return Date(timeIntervalSince1970: randomTime)
        }
    }
    

    附注Esqarrouth's answer 更正了最新的 Swift。

    【讨论】:

      猜你喜欢
      • 2022-01-23
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 2010-10-07
      • 2014-02-25
      • 1970-01-01
      相关资源
      最近更新 更多