1

我正在尝试进行数据清理,我正在尝试清理出生日期字段,但我希望它在某种程度上保持一致,即为相同的输入日期生成相同的随机数或出生日期。请帮助我解决这个问题。

我试过这个随机生成代码,但即使我提供相同的输入,它也会生成不同的代码。我希望随机输出保持一致。

import java.util.GregorianCalendar;

public class RandomDateOfBirth {

    public static void main(String[] args) {
        GregorianCalendar gc = new GregorianCalendar();
        int year = randBetween(1900, 2010);
        gc.set(gc.YEAR, year);
        int dayOfYear = randBetween(1, gc.getActualMaximum(gc.DAY_OF_YEAR));
        gc.set(gc.DAY_OF_YEAR, dayOfYear);
        System.out.println(gc.get(gc.YEAR) + "-" + (gc.get(gc.MONTH) + 1) + "-" + gc.get(gc.DAY_OF_MONTH));
    }

    public static int randBetween(int start, int end) {
        return start + (int) Math.round(Math.random() * (end - start));
    }

}
4

3 回答 3

1

请注意:如果您将敏感数据替换为可以重复确定的值,那么您并没有真正清理您的数据。如果您的目的是保护敏感数据,例如HIPAA,我建议您咨询负责人。他们应该接受有关如何适当地清理数据的培训。

还有一点需要澄清:你的标题是一个缩略词。根据定义,随机值不能被可预测地重复。

java.time

您的代码示例使用了糟糕的日期时间类,这些类在几年前被 JSR 310 中定义的现代java.time类所取代。对于仅日期值,请使用class.time LocalDate

只需分配任意天数

如果您想要任意但可重复的调整,只需添加或减去一定的天数。您可以为日期为奇数的日期任意分配负数(减法),并为日数为偶数的日期分配正数(加法)。

要确定偶数或奇数,请参阅此问题

int daysToAddToOddDayNumber = -2_555 ;
int daysToAddToEvenDayNumber = 2_101 ; 

LocalDate localDate = LocalDate.of( 1970 , Month.JANUARY , 1 );
boolean isEven = ( ( localDate.getDayOfMonth() & 1) == 0 ) ;
LocalDate adjusted = isEven ? localDate.plusDays( daysToAddToEvenDayNumber ) : localDate.plusDays( daysToAddToOddDayNumber ) ;

转储到控制台。

System.out.println( "localDate.toString(): " + localDate ) ;
System.out.println( "adjusted.toString(): " + adjusted ) ;

查看在 IdeOne.com 上实时运行的代码。

localDate.toString(): 1970-01-01

调整的.toString(): 1963-01-03

模糊要添加的天数

您可以通过对日期值进行散列来获得一些幻想,然后使用该散列结果来确定要添加的天数。同样,正如我之前所说,根据项目的需要(和法律!),这可能不符合充分的清理条件。

LocalDate localDate = LocalDate.of( 1970 , Month.JANUARY , 1 );
String input = localDate.toString();

MessageDigest md = null;
try
{
    md = MessageDigest.getInstance( "MD5" );
    md.update( input.getBytes() );
    byte[] digest = md.digest();
    int days = new BigInteger( 1 , digest ).mod( new BigInteger( "10000" ) ).intValue();
    LocalDate adjusted = localDate.minusDays( days );

    System.out.println( "localDate = " + localDate );
    System.out.println( "input = " + input );
    System.out.println( "days = " + days );
    System.out.println( "adjusted = " + adjusted );
} catch ( NoSuchAlgorithmException e )
{
    e.printStackTrace();
}

查看在 IdeOne.com 上实时运行的代码。

本地日期 = 1970-01-01

输入 = 1970-01-01

天 = 8491

调整2 = 1946-10-03

于 2019-10-08T04:35:37.167 回答
0

Random 类可以接受种子,这应该可以解决问题:

public static int randBetween (int start, int end){
    int seed = end +(start*10000);
    return start + new Random(seed).nextInt((end-start));
}

最重要的是:使用end +(start*10000)应该提供一个独特但可靠的种子。

于 2019-10-07T21:11:25.203 回答
0

假设你有一个方法generateRandomDate()并且你想清理日期列表,下面应该可以解决问题:

final Map<LocalDate, LocalDate> map = new HashMap<>();

List<LocalDate> initialDates = ...;
List<LocalDate> scrubbedDates =
    initialCalendars.stream()
                    .map(date -> map.computeIfAbsent(date, __ -> generateRandomDate()))
                    .collect(toList());

相同的日期将被随机生成的相同日期擦除。


generateRandomDate方法可以实现如下:

public static LocalDate generateRandomDate() {
    Random random = new Random();
    int minDay = (int) LocalDate.of(1900, 1, 1).toEpochDay();
    int maxDay = (int) LocalDate.of(2015, 1, 1).toEpochDay();
    long randomDay = minDay + random.nextInt(maxDay - minDay);

    return LocalDate.ofEpochDay(randomDay);
}

截断的日期生成代码是从这里借来的。

于 2019-10-08T04:38:21.280 回答