def checkForChanges(f, sde, isTable):
    """
    returns False if there are no changes

    """
    # try simple feature count first
    fCount = int(arcpy.GetCount_management(f).getOutput(0))
    sdeCount = int(arcpy.GetCount_management(sde).getOutput(0))
    if fCount != sdeCount:
        return True

    fields = [fld.name for fld in arcpy.ListFields(f)]

    # filter out shape fields
    if not isTable:
        fields = filter_fields(fields)

        d = arcpy.Describe(f)
        shapeType = d.shapeType
        if shapeType == 'Polygon':
            shapeToken = 'SHAPE@AREA'
        elif shapeType == 'Polyline':
            shapeToken = 'SHAPE@LENGTH'
        elif shapeType == 'Point':
            shapeToken = 'SHAPE@XY'
        else:
            shapeToken = 'SHAPE@JSON'
        fields.append(shapeToken)

        def parseShape(shapeValue):
            if shapeValue is None:
                return 0
            elif shapeType in ['Polygon', 'Polyline']:
                return shapeValue
            elif shapeType == 'Point':
                if shapeValue[0] is not None and shapeValue[1] is not None:
                    return shapeValue[0] + shapeValue[1]
                else:
                    return 0
            else:
                return shapeValue

        outputSR = arcpy.Describe(f).spatialReference
    else:
        outputSR = None

    changed = False
    with arcpy.da.SearchCursor(f, fields, sql_clause=(None, 'ORDER BY OBJECTID')) as fCursor, \
            arcpy.da.SearchCursor(sde, fields, sql_clause=(None, 'ORDER BY OBJECTID'),
                                  spatial_reference=outputSR) as sdeCursor:
        for fRow, sdeRow in izip(fCursor, sdeCursor):
            if fRow != sdeRow:
                # check shapes first
                if fRow[-1] != sdeRow[-1] and not isTable:
                    if shapeType not in ['Polygon', 'Polyline', 'Point']:
                        changed = True
                        break
                    fShape = parseShape(fRow[-1])
                    sdeShape = parseShape(sdeRow[-1])
                    try:
                        assert_almost_equal(fShape, sdeShape, -1)
                        # trim off shapes
                        fRow = list(fRow[:-1])
                        sdeRow = list(sdeRow[:-1])
                    except AssertionError:
                        changed = True
                        break

                # trim microseconds since they can be off by one between file and sde databases
                for i in range(len(fRow)):
                    if type(fRow[i]) is datetime:
                        fRow = list(fRow)
                        sdeRow = list(sdeRow)
                        fRow[i] = fRow[i].replace(microsecond=0)
                        try:
                            sdeRow[i] = sdeRow[i].replace(microsecond=0)
                        except:
                            pass

                # compare all values except OBJECTID
                if fRow[1:] != sdeRow[1:]:
                    changed = True
                    break

    return changed
returns False if there are no changes